diff options
author | Waldemar Brodkorb <wbx@openadk.org> | 2010-03-07 18:45:10 +0100 |
---|---|---|
committer | Waldemar Brodkorb <wbx@openadk.org> | 2010-03-07 18:45:10 +0100 |
commit | 17e34f2243446838d79a4a42e10777c5f100de2e (patch) | |
tree | 4c889a94babdf57b53fe7cf18b3fcff650181f52 | |
parent | 41fa61e1a26ffa8b637b824f54701fa402b52c70 (diff) |
add patch from rt4ls git
-rw-r--r-- | target/lemote/Makefile | 2 | ||||
-rw-r--r-- | target/lemote/kernel.config | 144 | ||||
-rw-r--r-- | target/lemote/patches/lemote.patch | 40947 | ||||
-rw-r--r-- | target/lemote/xorg.conf | 61 |
4 files changed, 41123 insertions, 31 deletions
diff --git a/target/lemote/Makefile b/target/lemote/Makefile index 7b1fda013..fa554dfaf 100644 --- a/target/lemote/Makefile +++ b/target/lemote/Makefile @@ -43,7 +43,7 @@ endif ifeq ($(FS),encrypted) imageinstall: $(BIN_DIR)/$(ROOTFSUSERTARBALL) createinitcrypt @echo 'The kernel+cryptinit file is: ${BIN_DIR}/${ADK_TARGET}-${FS}-kernel' - @echo "The RootFS tarball is: $(BIN_DIR)/$(ROOTFUSERSTARBALL)" + @echo "The RootFS tarball is: $(BIN_DIR)/$(ROOTFSUSERTARBALL)" @echo 'Boot your lemote via NFS or USB.' @echo 'Then create at least three partitions with fdisk:' @echo '/dev/sda1 (ext2)' diff --git a/target/lemote/kernel.config b/target/lemote/kernel.config index 22e8d01a6..33c8305bc 100644 --- a/target/lemote/kernel.config +++ b/target/lemote/kernel.config @@ -1,7 +1,7 @@ # # Automatically generated make config: don't edit # Linux kernel version: 2.6.33 -# Fri Mar 5 18:56:32 2010 +# Sun Mar 7 13:18:48 2010 # CONFIG_MIPS=y @@ -108,7 +108,6 @@ CONFIG_CPU_LOONGSON2F=y # CONFIG_CPU_SB1 is not set # CONFIG_CPU_CAVIUM_OCTEON is not set CONFIG_SYS_SUPPORTS_ZBOOT=y -CONFIG_SYS_SUPPORTS_ZBOOT_UART16550=y CONFIG_CPU_LOONGSON2=y CONFIG_SYS_HAS_CPU_LOONGSON2F=y CONFIG_SYS_SUPPORTS_32BIT_KERNEL=y @@ -226,12 +225,11 @@ CONFIG_SYSCTL=y CONFIG_ANON_INODES=y CONFIG_EMBEDDED=y CONFIG_SYSCTL_SYSCALL=y -CONFIG_KALLSYMS=y -# CONFIG_KALLSYMS_EXTRA_PASS is not set +# CONFIG_KALLSYMS is not set CONFIG_HOTPLUG=y CONFIG_PRINTK=y -CONFIG_BUG=y -# CONFIG_ELF_CORE is not set +# CONFIG_BUG is not set +CONFIG_ELF_CORE=y # CONFIG_PCSPKR_PLATFORM is not set # CONFIG_BASE_FULL is not set CONFIG_FUTEX=y @@ -279,11 +277,11 @@ CONFIG_BLOCK_COMPAT=y # CONFIG_IOSCHED_NOOP=y # CONFIG_IOSCHED_DEADLINE is not set -# CONFIG_IOSCHED_CFQ is not set +CONFIG_IOSCHED_CFQ=y # CONFIG_DEFAULT_DEADLINE is not set -# CONFIG_DEFAULT_CFQ is not set -CONFIG_DEFAULT_NOOP=y -CONFIG_DEFAULT_IOSCHED="noop" +CONFIG_DEFAULT_CFQ=y +# CONFIG_DEFAULT_NOOP is not set +CONFIG_DEFAULT_IOSCHED="cfq" # CONFIG_INLINE_SPIN_TRYLOCK is not set # CONFIG_INLINE_SPIN_TRYLOCK_BH is not set # CONFIG_INLINE_SPIN_LOCK is not set @@ -334,6 +332,7 @@ CONFIG_MMU=y # Executable file formats # CONFIG_BINFMT_ELF=y +# CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS is not set # CONFIG_HAVE_AOUT is not set # CONFIG_BINFMT_MISC is not set CONFIG_MIPS32_COMPAT=y @@ -374,9 +373,9 @@ CONFIG_CPU_FREQ_STAT=y # CONFIG_CPU_FREQ_DEFAULT_GOV_ONDEMAND is not set CONFIG_CPU_FREQ_DEFAULT_GOV_CONSERVATIVE=y CONFIG_CPU_FREQ_GOV_PERFORMANCE=y -# CONFIG_CPU_FREQ_GOV_POWERSAVE is not set -# CONFIG_CPU_FREQ_GOV_USERSPACE is not set -# CONFIG_CPU_FREQ_GOV_ONDEMAND is not set +CONFIG_CPU_FREQ_GOV_POWERSAVE=y +CONFIG_CPU_FREQ_GOV_USERSPACE=y +CONFIG_CPU_FREQ_GOV_ONDEMAND=y CONFIG_CPU_FREQ_GOV_CONSERVATIVE=y # @@ -393,13 +392,12 @@ CONFIG_PACKET_MMAP=y CONFIG_UNIX=y # CONFIG_NET_KEY is not set CONFIG_INET=y -CONFIG_IP_MULTICAST=y +# CONFIG_IP_MULTICAST is not set # CONFIG_IP_ADVANCED_ROUTER is not set CONFIG_IP_FIB_HASH=y # CONFIG_IP_PNP is not set # CONFIG_NET_IPIP is not set # CONFIG_NET_IPGRE is not set -# CONFIG_IP_MROUTE is not set # CONFIG_ARPD is not set CONFIG_SYN_COOKIES=y # CONFIG_INET_AH is not set @@ -735,7 +733,7 @@ CONFIG_WLAN=y CONFIG_INPUT=y # CONFIG_INPUT_FF_MEMLESS is not set # CONFIG_INPUT_POLLDEV is not set -# CONFIG_INPUT_SPARSEKMAP is not set +CONFIG_INPUT_SPARSEKMAP=y # # Userland interfaces @@ -763,7 +761,7 @@ CONFIG_INPUT_MOUSE=y CONFIG_MOUSE_PS2=y # CONFIG_MOUSE_PS2_ALPS is not set # CONFIG_MOUSE_PS2_LOGIPS2PP is not set -# CONFIG_MOUSE_PS2_SYNAPTICS is not set +CONFIG_MOUSE_PS2_SYNAPTICS=y # CONFIG_MOUSE_PS2_TRACKPOINT is not set # CONFIG_MOUSE_PS2_ELANTECH is not set # CONFIG_MOUSE_PS2_SENTELIC is not set @@ -825,7 +823,6 @@ CONFIG_UNIX98_PTYS=y # CONFIG_LEGACY_PTYS is not set # CONFIG_IPMI_HANDLER is not set # CONFIG_HW_RANDOM is not set -# CONFIG_RTC is not set # CONFIG_DTLK is not set # CONFIG_R3964 is not set # CONFIG_APPLICOM is not set @@ -840,8 +837,31 @@ CONFIG_DEVPORT=y # # CONFIG_PPS is not set # CONFIG_W1 is not set -# CONFIG_POWER_SUPPLY is not set -# CONFIG_HWMON is not set +CONFIG_POWER_SUPPLY=y +# CONFIG_POWER_SUPPLY_DEBUG is not set +# CONFIG_PDA_POWER is not set +# CONFIG_BATTERY_DS2760 is not set +CONFIG_HWMON=y +# CONFIG_HWMON_VID is not set +# CONFIG_HWMON_DEBUG_CHIP is not set + +# +# Native drivers +# +# CONFIG_SENSORS_I5K_AMB is not set +# CONFIG_SENSORS_F71805F is not set +# CONFIG_SENSORS_F71882FG is not set +# CONFIG_SENSORS_IT87 is not set +# CONFIG_SENSORS_PC87360 is not set +# CONFIG_SENSORS_PC87427 is not set +# CONFIG_SENSORS_SIS5595 is not set +# CONFIG_SENSORS_SMSC47M1 is not set +# CONFIG_SENSORS_SMSC47B397 is not set +# CONFIG_SENSORS_VIA686A is not set +# CONFIG_SENSORS_VT1211 is not set +# CONFIG_SENSORS_VT8231 is not set +# CONFIG_SENSORS_W83627HF is not set +# CONFIG_SENSORS_W83627EHF is not set # CONFIG_THERMAL is not set # CONFIG_WATCHDOG is not set CONFIG_SSB_POSSIBLE=y @@ -864,10 +884,10 @@ CONFIG_SSB_POSSIBLE=y # # Graphics support # -# CONFIG_VGA_ARB is not set +CONFIG_VGA_ARB=y # CONFIG_DRM is not set # CONFIG_VGASTATE is not set -# CONFIG_VIDEO_OUTPUT_CONTROL is not set +CONFIG_VIDEO_OUTPUT_CONTROL=y CONFIG_FB=y # CONFIG_FIRMWARE_EDID is not set # CONFIG_FB_DDC is not set @@ -885,7 +905,7 @@ CONFIG_FB_CFB_IMAGEBLIT=y # CONFIG_FB_MACMODES is not set # CONFIG_FB_BACKLIGHT is not set CONFIG_FB_MODE_HELPERS=y -CONFIG_FB_TILEBLITTING=y +# CONFIG_FB_TILEBLITTING is not set # # Frame buffer hardware drivers @@ -927,7 +947,11 @@ CONFIG_BACKLIGHT_CLASS_DEVICE=y # # Display device support # -# CONFIG_DISPLAY_SUPPORT is not set +CONFIG_DISPLAY_SUPPORT=y + +# +# Display hardware drivers +# # # Console display driver support @@ -937,7 +961,7 @@ CONFIG_BACKLIGHT_CLASS_DEVICE=y CONFIG_DUMMY_CONSOLE=y CONFIG_FRAMEBUFFER_CONSOLE=y # CONFIG_FRAMEBUFFER_CONSOLE_DETECT_PRIMARY is not set -CONFIG_FRAMEBUFFER_CONSOLE_ROTATION=y +# CONFIG_FRAMEBUFFER_CONSOLE_ROTATION is not set # CONFIG_FONTS is not set CONFIG_FONT_8x8=y CONFIG_FONT_8x16=y @@ -976,8 +1000,8 @@ CONFIG_USB=y # # Miscellaneous USB options # -CONFIG_USB_DEVICEFS=y -CONFIG_USB_DEVICE_CLASS=y +# CONFIG_USB_DEVICEFS is not set +# CONFIG_USB_DEVICE_CLASS is not set CONFIG_USB_DYNAMIC_MINORS=y CONFIG_USB_SUSPEND=y # CONFIG_USB_OTG is not set @@ -1069,12 +1093,70 @@ CONFIG_USB_OHCI_LITTLE_ENDIAN=y # # CONFIG_NOP_USB_XCEIV is not set # CONFIG_UWB is not set -# CONFIG_MMC is not set +CONFIG_MMC=y +# CONFIG_MMC_DEBUG is not set +# CONFIG_MMC_UNSAFE_RESUME is not set + +# +# MMC/SD/SDIO Card Drivers +# +CONFIG_MMC_BLOCK=y +CONFIG_MMC_BLOCK_BOUNCE=y +# CONFIG_SDIO_UART is not set +# CONFIG_MMC_TEST is not set + +# +# MMC/SD/SDIO Host Controller Drivers +# +# CONFIG_MMC_SDHCI is not set +# CONFIG_MMC_AT91 is not set +# CONFIG_MMC_ATMELMCI is not set +# CONFIG_MMC_TIFM_SD is not set +# CONFIG_MMC_CB710 is not set +# CONFIG_MMC_VIA_SDMMC is not set # CONFIG_MEMSTICK is not set # CONFIG_NEW_LEDS is not set # CONFIG_ACCESSIBILITY is not set # CONFIG_INFINIBAND is not set -# CONFIG_RTC_CLASS is not set +CONFIG_RTC_LIB=y +CONFIG_RTC_CLASS=y +CONFIG_RTC_HCTOSYS=y +CONFIG_RTC_HCTOSYS_DEVICE="rtc0" +# CONFIG_RTC_DEBUG is not set + +# +# RTC interfaces +# +CONFIG_RTC_INTF_SYSFS=y +CONFIG_RTC_INTF_PROC=y +CONFIG_RTC_INTF_DEV=y +# CONFIG_RTC_INTF_DEV_UIE_EMUL is not set +# CONFIG_RTC_DRV_TEST is not set + +# +# SPI RTC drivers +# + +# +# Platform RTC drivers +# +CONFIG_RTC_DRV_CMOS=y +# CONFIG_RTC_DRV_DS1286 is not set +# CONFIG_RTC_DRV_DS1511 is not set +# CONFIG_RTC_DRV_DS1553 is not set +# CONFIG_RTC_DRV_DS1742 is not set +# CONFIG_RTC_DRV_STK17TA8 is not set +# CONFIG_RTC_DRV_M48T86 is not set +# CONFIG_RTC_DRV_M48T35 is not set +# CONFIG_RTC_DRV_M48T59 is not set +# CONFIG_RTC_DRV_MSM6242 is not set +# CONFIG_RTC_DRV_BQ4802 is not set +# CONFIG_RTC_DRV_RP5C01 is not set +# CONFIG_RTC_DRV_V3020 is not set + +# +# on-CPU RTC drivers +# # CONFIG_DMADEVICES is not set # CONFIG_AUXDISPLAY is not set # CONFIG_UIO is not set @@ -1121,7 +1203,9 @@ CONFIG_STAGING=y # CONFIG_STRIP is not set # CONFIG_WAVELAN is not set CONFIG_FB_SM7XX=y -# CONFIG_FB_SM7XX_ACCEL is not set +CONFIG_MIPS_PLATFORM_DEVICES=y +CONFIG_LEMOTE_YEELOONG2F=y +# CONFIG_LEMOTE_LYNLOONG2F is not set # # File systems diff --git a/target/lemote/patches/lemote.patch b/target/lemote/patches/lemote.patch new file mode 100644 index 000000000..edb778459 --- /dev/null +++ b/target/lemote/patches/lemote.patch @@ -0,0 +1,40947 @@ +diff -Nur linux-2.6.33/arch/mips/boot/compressed/dbg.c linux-lemote/arch/mips/boot/compressed/dbg.c +--- linux-2.6.33/arch/mips/boot/compressed/dbg.c 2010-02-24 19:52:17.000000000 +0100 ++++ linux-lemote/arch/mips/boot/compressed/dbg.c 2010-03-06 16:42:59.000000000 +0100 +@@ -9,7 +9,7 @@ + #include <linux/init.h> + #include <linux/types.h> + +-void __attribute__ ((weak)) putc(char c) ++void __weak putc(char c) + { + } + +diff -Nur linux-2.6.33/arch/mips/boot/compressed/decompress.c linux-lemote/arch/mips/boot/compressed/decompress.c +--- linux-2.6.33/arch/mips/boot/compressed/decompress.c 2010-02-24 19:52:17.000000000 +0100 ++++ linux-lemote/arch/mips/boot/compressed/decompress.c 2010-03-06 16:42:59.000000000 +0100 +@@ -5,8 +5,8 @@ + * Author: Matt Porter <mporter@mvista.com> Derived from + * arch/ppc/boot/prep/misc.c + * +- * Copyright (C) 2009 Lemote, Inc. & Institute of Computing Technology +- * Author: Wu Zhangjin <wuzj@lemote.com> ++ * Copyright (C) 2009 Lemote, Inc. ++ * Author: Wu Zhangjin <wuzhangjin@gmail.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 +diff -Nur linux-2.6.33/arch/mips/boot/compressed/ld.script linux-lemote/arch/mips/boot/compressed/ld.script +--- linux-2.6.33/arch/mips/boot/compressed/ld.script 2010-02-24 19:52:17.000000000 +0100 ++++ linux-lemote/arch/mips/boot/compressed/ld.script 2010-03-06 16:42:59.000000000 +0100 +@@ -2,7 +2,7 @@ + * ld.script for compressed kernel support of MIPS + * + * Copyright (C) 2009 Lemote Inc. +- * Author: Wu Zhangjin <wuzj@lemote.com> ++ * Author: Wu Zhangjin <wuzhangjin@gmail.com> + */ + + OUTPUT_ARCH(mips) +@@ -29,8 +29,8 @@ + __image_end = .; + CONSTRUCTORS + } +- .sdata : { *(.sdata) } +- . = ALIGN(4); ++ .sdata : { *(.sdata) } ++ . = ALIGN(4); + _edata = .; /* End of data section */ + + /* BSS */ +diff -Nur linux-2.6.33/arch/mips/boot/compressed/Makefile linux-lemote/arch/mips/boot/compressed/Makefile +--- linux-2.6.33/arch/mips/boot/compressed/Makefile 2010-02-24 19:52:17.000000000 +0100 ++++ linux-lemote/arch/mips/boot/compressed/Makefile 2010-03-06 16:42:59.000000000 +0100 +@@ -9,7 +9,7 @@ + # modified by Cort (cort@cs.nmt.edu) + # + # Copyright (C) 2009 Lemote Inc. & DSLab, Lanzhou University +-# Author: Wu Zhangjin <wuzj@lemote.com> ++# Author: Wu Zhangjin <wuzhangjin@gmail.com> + # + + # compressed kernel load addr: VMLINUZ_LOAD_ADDRESS > VMLINUX_LOAD_ADDRESS + VMLINUX_SIZE +@@ -27,15 +27,17 @@ + KBUILD_CFLAGS := $(shell echo $(KBUILD_CFLAGS) | sed -e "s/-pg//") + + KBUILD_CFLAGS := $(LINUXINCLUDE) $(KBUILD_CFLAGS) -D__KERNEL__ \ +- -DBOOT_HEAP_SIZE=$(BOOT_HEAP_SIZE) -D"VMLINUX_LOAD_ADDRESS_ULL=$(VMLINUX_LOAD_ADDRESS)ull" \ ++ -DBOOT_HEAP_SIZE=$(BOOT_HEAP_SIZE) -D"VMLINUX_LOAD_ADDRESS_ULL=$(VMLINUX_LOAD_ADDRESS)ull" + + KBUILD_AFLAGS := $(LINUXINCLUDE) $(KBUILD_AFLAGS) -D__ASSEMBLY__ \ +- -DKERNEL_ENTRY=0x$(shell $(NM) $(objtree)/$(KBUILD_IMAGE) 2>/dev/null | grep " kernel_entry" | cut -f1 -d \ ) \ +- -DBOOT_HEAP_SIZE=$(BOOT_HEAP_SIZE) ++ -DBOOT_HEAP_SIZE=$(BOOT_HEAP_SIZE) \ ++ -DKERNEL_ENTRY=0x$(shell $(NM) $(objtree)/$(KBUILD_IMAGE) 2>/dev/null | grep " kernel_entry" | cut -f1 -d \ ) + + obj-y := $(obj)/head.o $(obj)/decompress.o $(obj)/dbg.o + ++ifdef CONFIG_DEBUG_ZBOOT + obj-$(CONFIG_SYS_SUPPORTS_ZBOOT_UART16550) += $(obj)/uart-16550.o ++endif + + OBJCOPYFLAGS_vmlinux.bin := $(OBJCOPYFLAGS) -O binary -R .comment -S + $(obj)/vmlinux.bin: $(KBUILD_IMAGE) +diff -Nur linux-2.6.33/arch/mips/configs/fuloong2e_defconfig linux-lemote/arch/mips/configs/fuloong2e_defconfig +--- linux-2.6.33/arch/mips/configs/fuloong2e_defconfig 2010-02-24 19:52:17.000000000 +0100 ++++ linux-lemote/arch/mips/configs/fuloong2e_defconfig 2010-03-06 16:42:59.000000000 +0100 +@@ -1,7 +1,7 @@ + # + # Automatically generated make config: don't edit +-# Linux kernel version: 2.6.32-rc4 +-# Fri Oct 16 13:18:01 2009 ++# Linux kernel version: 2.6.33 ++# Mon Mar 1 23:44:14 2010 + # + CONFIG_MIPS=y + +@@ -27,6 +27,7 @@ + # CONFIG_PNX8550_STB810 is not set + # CONFIG_PMC_MSP is not set + # CONFIG_PMC_YOSEMITE is not set ++# CONFIG_POWERTV is not set + # CONFIG_SGI_IP22 is not set + # CONFIG_SGI_IP27 is not set + # CONFIG_SGI_IP28 is not set +@@ -49,6 +50,8 @@ + # CONFIG_ALCHEMY_GPIO_INDIRECT is not set + CONFIG_ARCH_SPARSEMEM_ENABLE=y + CONFIG_LEMOTE_FULOONG2E=y ++# CONFIG_LEMOTE_MACH2F is not set ++CONFIG_LOONGSON_UART_BASE=y + CONFIG_RWSEM_GENERIC_SPINLOCK=y + # CONFIG_ARCH_HAS_ILOG2_U32 is not set + # CONFIG_ARCH_HAS_ILOG2_U64 is not set +@@ -67,7 +70,6 @@ + CONFIG_CSRC_R4K=y + CONFIG_DMA_NONCOHERENT=y + CONFIG_DMA_NEED_PCI_MAP_STATE=y +-CONFIG_EARLY_PRINTK=y + CONFIG_SYS_HAS_EARLY_PRINTK=y + CONFIG_I8259=y + # CONFIG_NO_IOPORT is not set +@@ -84,6 +86,7 @@ + # CPU selection + # + CONFIG_CPU_LOONGSON2E=y ++# CONFIG_CPU_LOONGSON2F is not set + # CONFIG_CPU_MIPS32_R1 is not set + # CONFIG_CPU_MIPS32_R2 is not set + # CONFIG_CPU_MIPS64_R1 is not set +@@ -106,7 +109,6 @@ + # CONFIG_CPU_SB1 is not set + # CONFIG_CPU_CAVIUM_OCTEON is not set + CONFIG_SYS_SUPPORTS_ZBOOT=y +-CONFIG_SYS_SUPPORTS_ZBOOT_UART16550=y + CONFIG_CPU_LOONGSON2=y + CONFIG_SYS_HAS_CPU_LOONGSON2E=y + CONFIG_SYS_SUPPORTS_32BIT_KERNEL=y +@@ -134,7 +136,6 @@ + CONFIG_GENERIC_IRQ_PROBE=y + CONFIG_CPU_SUPPORTS_HIGHMEM=y + CONFIG_SYS_SUPPORTS_HIGHMEM=y +-CONFIG_ARCH_FLATMEM_ENABLE=y + CONFIG_ARCH_POPULATES_NODE_MAP=y + CONFIG_SELECT_MEMORY_MODEL=y + # CONFIG_FLATMEM_MANUAL is not set +@@ -143,23 +144,18 @@ + CONFIG_SPARSEMEM=y + CONFIG_HAVE_MEMORY_PRESENT=y + CONFIG_SPARSEMEM_STATIC=y +- +-# +-# Memory hotplug is currently incompatible with Software Suspend +-# + CONFIG_PAGEFLAGS_EXTENDED=y + CONFIG_SPLIT_PTLOCK_CPUS=4 + CONFIG_PHYS_ADDR_T_64BIT=y + CONFIG_ZONE_DMA_FLAG=0 + CONFIG_VIRT_TO_BUS=y +-CONFIG_HAVE_MLOCK=y +-CONFIG_HAVE_MLOCKED_PAGE_BIT=y + # CONFIG_KSM is not set + CONFIG_DEFAULT_MMAP_MIN_ADDR=4096 + CONFIG_TICK_ONESHOT=y + CONFIG_NO_HZ=y + CONFIG_HIGH_RES_TIMERS=y + CONFIG_GENERIC_CLOCKEVENTS_BUILD=y ++CONFIG_CPU_SUPPORTS_HR_SCHED_CLOCK=y + # CONFIG_HZ_48 is not set + # CONFIG_HZ_100 is not set + # CONFIG_HZ_128 is not set +@@ -190,9 +186,11 @@ + CONFIG_HAVE_KERNEL_GZIP=y + CONFIG_HAVE_KERNEL_BZIP2=y + CONFIG_HAVE_KERNEL_LZMA=y ++CONFIG_HAVE_KERNEL_LZO=y + CONFIG_KERNEL_GZIP=y + # CONFIG_KERNEL_BZIP2 is not set + # CONFIG_KERNEL_LZMA is not set ++# CONFIG_KERNEL_LZO is not set + CONFIG_SWAP=y + CONFIG_SYSVIPC=y + CONFIG_SYSVIPC_SYSCTL=y +@@ -208,6 +206,7 @@ + # + CONFIG_TREE_RCU=y + # CONFIG_TREE_PREEMPT_RCU is not set ++# CONFIG_TINY_RCU is not set + # CONFIG_RCU_TRACE is not set + CONFIG_RCU_FANOUT=64 + # CONFIG_RCU_FANOUT_EXACT is not set +@@ -217,8 +216,7 @@ + CONFIG_LOG_BUF_SHIFT=14 + # CONFIG_GROUP_SCHED is not set + # CONFIG_CGROUPS is not set +-CONFIG_SYSFS_DEPRECATED=y +-CONFIG_SYSFS_DEPRECATED_V2=y ++# CONFIG_SYSFS_DEPRECATED_V2 is not set + # CONFIG_RELAY is not set + CONFIG_NAMESPACES=y + # CONFIG_UTS_NS is not set +@@ -268,6 +266,7 @@ + # + # CONFIG_GCOV_KERNEL is not set + CONFIG_SLOW_WORK=y ++# CONFIG_SLOW_WORK_DEBUG is not set + CONFIG_HAVE_GENERIC_DMA_COHERENT=y + CONFIG_SLABINFO=y + CONFIG_RT_MUTEXES=y +@@ -287,14 +286,41 @@ + # IO Schedulers + # + CONFIG_IOSCHED_NOOP=y +-CONFIG_IOSCHED_AS=y + CONFIG_IOSCHED_DEADLINE=y + CONFIG_IOSCHED_CFQ=y +-# CONFIG_DEFAULT_AS is not set + # CONFIG_DEFAULT_DEADLINE is not set + CONFIG_DEFAULT_CFQ=y + # CONFIG_DEFAULT_NOOP is not set + CONFIG_DEFAULT_IOSCHED="cfq" ++# CONFIG_INLINE_SPIN_TRYLOCK is not set ++# CONFIG_INLINE_SPIN_TRYLOCK_BH is not set ++# CONFIG_INLINE_SPIN_LOCK is not set ++# CONFIG_INLINE_SPIN_LOCK_BH is not set ++# CONFIG_INLINE_SPIN_LOCK_IRQ is not set ++# CONFIG_INLINE_SPIN_LOCK_IRQSAVE is not set ++CONFIG_INLINE_SPIN_UNLOCK=y ++# CONFIG_INLINE_SPIN_UNLOCK_BH is not set ++CONFIG_INLINE_SPIN_UNLOCK_IRQ=y ++# CONFIG_INLINE_SPIN_UNLOCK_IRQRESTORE is not set ++# CONFIG_INLINE_READ_TRYLOCK is not set ++# CONFIG_INLINE_READ_LOCK is not set ++# CONFIG_INLINE_READ_LOCK_BH is not set ++# CONFIG_INLINE_READ_LOCK_IRQ is not set ++# CONFIG_INLINE_READ_LOCK_IRQSAVE is not set ++CONFIG_INLINE_READ_UNLOCK=y ++# CONFIG_INLINE_READ_UNLOCK_BH is not set ++CONFIG_INLINE_READ_UNLOCK_IRQ=y ++# CONFIG_INLINE_READ_UNLOCK_IRQRESTORE is not set ++# CONFIG_INLINE_WRITE_TRYLOCK is not set ++# CONFIG_INLINE_WRITE_LOCK is not set ++# CONFIG_INLINE_WRITE_LOCK_BH is not set ++# CONFIG_INLINE_WRITE_LOCK_IRQ is not set ++# CONFIG_INLINE_WRITE_LOCK_IRQSAVE is not set ++CONFIG_INLINE_WRITE_UNLOCK=y ++# CONFIG_INLINE_WRITE_UNLOCK_BH is not set ++CONFIG_INLINE_WRITE_UNLOCK_IRQ=y ++# CONFIG_INLINE_WRITE_UNLOCK_IRQRESTORE is not set ++# CONFIG_MUTEX_SPIN_ON_OWNER is not set + CONFIG_FREEZER=y + + # +@@ -340,7 +366,6 @@ + CONFIG_PM_STD_PARTITION="/dev/hda3" + # CONFIG_PM_RUNTIME is not set + CONFIG_NET=y +-CONFIG_COMPAT_NETLINK_MESSAGES=y + + # + # Networking options +@@ -491,10 +516,6 @@ + # CONFIG_AF_RXRPC is not set + CONFIG_WIRELESS=y + # CONFIG_CFG80211 is not set +-CONFIG_CFG80211_DEFAULT_PS_VALUE=0 +-CONFIG_WIRELESS_OLD_REGULATORY=y +-CONFIG_WIRELESS_EXT=y +-CONFIG_WIRELESS_EXT_SYSFS=y + # CONFIG_LIB80211 is not set + + # +@@ -617,6 +638,10 @@ + # CONFIG_BLK_DEV_COW_COMMON is not set + CONFIG_BLK_DEV_LOOP=y + CONFIG_BLK_DEV_CRYPTOLOOP=m ++ ++# ++# DRBD disabled because PROC_FS, INET or CONNECTOR not selected ++# + # CONFIG_BLK_DEV_NBD is not set + # CONFIG_BLK_DEV_SX8 is not set + # CONFIG_BLK_DEV_UB is not set +@@ -755,7 +780,7 @@ + # + + # +-# See the help texts for more information. ++# The newer stack is recommended. + # + # CONFIG_FIREWIRE is not set + # CONFIG_IEEE1394 is not set +@@ -798,6 +823,7 @@ + # CONFIG_SMC91X is not set + # CONFIG_DM9000 is not set + # CONFIG_ETHOC is not set ++# CONFIG_SMSC911X is not set + # CONFIG_NET_VENDOR_RACAL is not set + # CONFIG_DNET is not set + # CONFIG_NET_TULIP is not set +@@ -888,8 +914,10 @@ + # CONFIG_BE2NET is not set + # CONFIG_TR is not set + CONFIG_WLAN=y +-# CONFIG_WLAN_PRE80211 is not set +-# CONFIG_WLAN_80211 is not set ++# CONFIG_ATMEL is not set ++# CONFIG_PRISM54 is not set ++# CONFIG_USB_ZD1201 is not set ++# CONFIG_HOSTAP is not set + + # + # Enable WiMAX (Networking options) to see the WiMAX drivers +@@ -926,6 +954,7 @@ + # CONFIG_NETCONSOLE is not set + # CONFIG_NETPOLL is not set + # CONFIG_NET_POLL_CONTROLLER is not set ++# CONFIG_VMXNET3 is not set + # CONFIG_ISDN is not set + # CONFIG_PHONE is not set + +@@ -935,6 +964,7 @@ + CONFIG_INPUT=y + CONFIG_INPUT_FF_MEMLESS=y + # CONFIG_INPUT_POLLDEV is not set ++# CONFIG_INPUT_SPARSEKMAP is not set + + # + # Userland interfaces +@@ -992,6 +1022,7 @@ + # CONFIG_SERIO_PCIPS2 is not set + CONFIG_SERIO_LIBPS2=y + # CONFIG_SERIO_RAW is not set ++# CONFIG_SERIO_ALTERA_PS2 is not set + # CONFIG_GAMEPORT is not set + + # +@@ -1078,11 +1109,6 @@ + # CONFIG_I2C_TINY_USB is not set + + # +-# Graphics adapter I2C/DDC channel drivers +-# +-# CONFIG_I2C_VOODOO3 is not set +- +-# + # Other I2C/SMBus bus drivers + # + # CONFIG_I2C_ELEKTOR is not set +@@ -1093,7 +1119,6 @@ + # + # Miscellaneous I2C Chip support + # +-# CONFIG_DS1682 is not set + # CONFIG_SENSORS_TSL2550 is not set + # CONFIG_I2C_DEBUG_CORE is not set + # CONFIG_I2C_DEBUG_ALGO is not set +@@ -1125,7 +1150,6 @@ + # CONFIG_HTC_PASIC3 is not set + # CONFIG_MFD_TMIO is not set + # CONFIG_MFD_WM8400 is not set +-# CONFIG_MFD_WM831X is not set + # CONFIG_MFD_WM8350_I2C is not set + # CONFIG_MFD_PCF50633 is not set + # CONFIG_AB3100_CORE is not set +@@ -1271,6 +1295,7 @@ + # CONFIG_SND_OXYGEN is not set + # CONFIG_SND_CS4281 is not set + # CONFIG_SND_CS46XX is not set ++# CONFIG_SND_CS5535AUDIO is not set + # CONFIG_SND_CTXFI is not set + # CONFIG_SND_DARLA20 is not set + # CONFIG_SND_GINA20 is not set +@@ -1482,6 +1507,7 @@ + # TI VLYNQ + # + # CONFIG_STAGING is not set ++CONFIG_MIPS_PLATFORM_DEVICES=y + + # + # File systems +@@ -1522,8 +1548,8 @@ + # CONFIG_QUOTA is not set + CONFIG_AUTOFS_FS=y + CONFIG_AUTOFS4_FS=y +-CONFIG_FUSE_FS=y +-# CONFIG_CUSE is not set ++CONFIG_FUSE_FS=m ++CONFIG_CUSE=m + + # + # Caches +@@ -1700,6 +1726,11 @@ + # CONFIG_RCU_CPU_STALL_DETECTOR is not set + CONFIG_SYSCTL_SYSCALL_CHECK=y + CONFIG_NOP_TRACER=y ++CONFIG_HAVE_FUNCTION_TRACER=y ++CONFIG_HAVE_FUNCTION_GRAPH_TRACER=y ++CONFIG_HAVE_FUNCTION_TRACE_MCOUNT_TEST=y ++CONFIG_HAVE_DYNAMIC_FTRACE=y ++CONFIG_HAVE_FTRACE_MCOUNT_RECORD=y + CONFIG_RING_BUFFER=y + CONFIG_EVENT_TRACING=y + CONFIG_CONTEXT_SWITCH_TRACER=y +@@ -1710,6 +1741,7 @@ + # CONFIG_DYNAMIC_DEBUG is not set + # CONFIG_SAMPLES is not set + CONFIG_HAVE_ARCH_KGDB=y ++CONFIG_EARLY_PRINTK=y + # CONFIG_CMDLINE_BOOL is not set + + # +@@ -1718,7 +1750,11 @@ + # CONFIG_KEYS is not set + # CONFIG_SECURITY is not set + # CONFIG_SECURITYFS is not set +-CONFIG_SECURITY_FILE_CAPABILITIES=y ++# CONFIG_DEFAULT_SECURITY_SELINUX is not set ++# CONFIG_DEFAULT_SECURITY_SMACK is not set ++# CONFIG_DEFAULT_SECURITY_TOMOYO is not set ++CONFIG_DEFAULT_SECURITY_DAC=y ++CONFIG_DEFAULT_SECURITY="" + CONFIG_CRYPTO=y + + # +diff -Nur linux-2.6.33/arch/mips/configs/lemote2f_defconfig linux-lemote/arch/mips/configs/lemote2f_defconfig +--- linux-2.6.33/arch/mips/configs/lemote2f_defconfig 2010-02-24 19:52:17.000000000 +0100 ++++ linux-lemote/arch/mips/configs/lemote2f_defconfig 2010-03-06 16:42:59.000000000 +0100 +@@ -1,7 +1,7 @@ + # + # Automatically generated make config: don't edit +-# Linux kernel version: 2.6.32-rc6 +-# Mon Nov 9 23:42:42 2009 ++# Linux kernel version: 2.6.33 ++# Mon Mar 1 23:36:53 2010 + # + CONFIG_MIPS=y + +@@ -27,6 +27,7 @@ + # CONFIG_PNX8550_STB810 is not set + # CONFIG_PMC_MSP is not set + # CONFIG_PMC_YOSEMITE is not set ++# CONFIG_POWERTV is not set + # CONFIG_SGI_IP22 is not set + # CONFIG_SGI_IP27 is not set + # CONFIG_SGI_IP28 is not set +@@ -51,6 +52,9 @@ + # CONFIG_LEMOTE_FULOONG2E is not set + CONFIG_LEMOTE_MACH2F=y + CONFIG_CS5536=y ++CONFIG_CS5536_MFGPT=y ++CONFIG_LOONGSON_SUSPEND=y ++CONFIG_LOONGSON_UART_BASE=y + CONFIG_RWSEM_GENERIC_SPINLOCK=y + # CONFIG_ARCH_HAS_ILOG2_U32 is not set + # CONFIG_ARCH_HAS_ILOG2_U64 is not set +@@ -63,13 +67,8 @@ + CONFIG_GENERIC_CMOS_UPDATE=y + CONFIG_SCHED_OMIT_FRAME_POINTER=y + CONFIG_GENERIC_HARDIRQS_NO__DO_IRQ=y +-CONFIG_CEVT_R4K_LIB=y +-CONFIG_CEVT_R4K=y +-CONFIG_CSRC_R4K_LIB=y +-CONFIG_CSRC_R4K=y + CONFIG_DMA_NONCOHERENT=y + CONFIG_DMA_NEED_PCI_MAP_STATE=y +-CONFIG_EARLY_PRINTK=y + CONFIG_SYS_HAS_EARLY_PRINTK=y + CONFIG_I8259=y + # CONFIG_NO_IOPORT is not set +@@ -109,13 +108,15 @@ + # CONFIG_CPU_SB1 is not set + # CONFIG_CPU_CAVIUM_OCTEON is not set + CONFIG_SYS_SUPPORTS_ZBOOT=y +-CONFIG_SYS_SUPPORTS_ZBOOT_UART16550=y + CONFIG_CPU_LOONGSON2=y + CONFIG_SYS_HAS_CPU_LOONGSON2F=y + CONFIG_SYS_SUPPORTS_32BIT_KERNEL=y + CONFIG_SYS_SUPPORTS_64BIT_KERNEL=y + CONFIG_CPU_SUPPORTS_32BIT_KERNEL=y + CONFIG_CPU_SUPPORTS_64BIT_KERNEL=y ++CONFIG_CPU_SUPPORTS_CPUFREQ=y ++CONFIG_CPU_SUPPORTS_ADDRWINCFG=y ++CONFIG_CPU_SUPPORTS_UNCACHED_ACCELERATED=y + + # + # Kernel type +@@ -137,7 +138,6 @@ + CONFIG_GENERIC_IRQ_PROBE=y + CONFIG_CPU_SUPPORTS_HIGHMEM=y + CONFIG_SYS_SUPPORTS_HIGHMEM=y +-CONFIG_ARCH_FLATMEM_ENABLE=y + CONFIG_ARCH_POPULATES_NODE_MAP=y + CONFIG_SELECT_MEMORY_MODEL=y + # CONFIG_FLATMEM_MANUAL is not set +@@ -146,17 +146,11 @@ + CONFIG_SPARSEMEM=y + CONFIG_HAVE_MEMORY_PRESENT=y + CONFIG_SPARSEMEM_STATIC=y +- +-# +-# Memory hotplug is currently incompatible with Software Suspend +-# + CONFIG_PAGEFLAGS_EXTENDED=y + CONFIG_SPLIT_PTLOCK_CPUS=4 + CONFIG_PHYS_ADDR_T_64BIT=y + CONFIG_ZONE_DMA_FLAG=0 + CONFIG_VIRT_TO_BUS=y +-CONFIG_HAVE_MLOCK=y +-CONFIG_HAVE_MLOCKED_PAGE_BIT=y + # CONFIG_KSM is not set + CONFIG_DEFAULT_MMAP_MIN_ADDR=4096 + CONFIG_TICK_ONESHOT=y +@@ -175,7 +169,7 @@ + # CONFIG_PREEMPT_NONE is not set + # CONFIG_PREEMPT_VOLUNTARY is not set + CONFIG_PREEMPT=y +-# CONFIG_KEXEC is not set ++CONFIG_KEXEC=y + # CONFIG_SECCOMP is not set + CONFIG_LOCKDEP_SUPPORT=y + CONFIG_STACKTRACE_SUPPORT=y +@@ -194,9 +188,11 @@ + CONFIG_HAVE_KERNEL_GZIP=y + CONFIG_HAVE_KERNEL_BZIP2=y + CONFIG_HAVE_KERNEL_LZMA=y +-# CONFIG_KERNEL_GZIP is not set ++CONFIG_HAVE_KERNEL_LZO=y ++CONFIG_KERNEL_GZIP=y + # CONFIG_KERNEL_BZIP2 is not set +-CONFIG_KERNEL_LZMA=y ++# CONFIG_KERNEL_LZMA is not set ++# CONFIG_KERNEL_LZO is not set + CONFIG_SWAP=y + CONFIG_SYSVIPC=y + CONFIG_SYSVIPC_SYSCTL=y +@@ -211,6 +207,7 @@ + # + CONFIG_TREE_RCU=y + # CONFIG_TREE_PREEMPT_RCU is not set ++# CONFIG_TINY_RCU is not set + # CONFIG_RCU_TRACE is not set + CONFIG_RCU_FANOUT=64 + # CONFIG_RCU_FANOUT_EXACT is not set +@@ -220,11 +217,15 @@ + CONFIG_LOG_BUF_SHIFT=15 + # CONFIG_GROUP_SCHED is not set + # CONFIG_CGROUPS is not set +-CONFIG_SYSFS_DEPRECATED=y +-CONFIG_SYSFS_DEPRECATED_V2=y ++# CONFIG_SYSFS_DEPRECATED_V2 is not set + # CONFIG_RELAY is not set + # CONFIG_NAMESPACES is not set +-# CONFIG_BLK_DEV_INITRD is not set ++CONFIG_BLK_DEV_INITRD=y ++CONFIG_INITRAMFS_SOURCE="" ++CONFIG_RD_GZIP=y ++CONFIG_RD_BZIP2=y ++CONFIG_RD_LZMA=y ++# CONFIG_RD_LZO is not set + # CONFIG_CC_OPTIMIZE_FOR_SIZE is not set + CONFIG_SYSCTL=y + CONFIG_ANON_INODES=y +@@ -251,21 +252,24 @@ + # + CONFIG_VM_EVENT_COUNTERS=y + CONFIG_PCI_QUIRKS=y +-CONFIG_SLUB_DEBUG=y ++# CONFIG_SLUB_DEBUG is not set + CONFIG_COMPAT_BRK=y + # CONFIG_SLAB is not set + CONFIG_SLUB=y + # CONFIG_SLOB is not set +-# CONFIG_PROFILING is not set ++CONFIG_PROFILING=y ++CONFIG_TRACEPOINTS=y ++CONFIG_OPROFILE=m + CONFIG_HAVE_OPROFILE=y + CONFIG_HAVE_SYSCALL_WRAPPERS=y + + # + # GCOV-based kernel profiling + # +-# CONFIG_SLOW_WORK is not set ++# CONFIG_GCOV_KERNEL is not set ++CONFIG_SLOW_WORK=y ++# CONFIG_SLOW_WORK_DEBUG is not set + CONFIG_HAVE_GENERIC_DMA_COHERENT=y +-CONFIG_SLABINFO=y + CONFIG_RT_MUTEXES=y + CONFIG_BASE_SMALL=0 + CONFIG_MODULES=y +@@ -283,14 +287,41 @@ + # IO Schedulers + # + CONFIG_IOSCHED_NOOP=y +-CONFIG_IOSCHED_AS=y +-CONFIG_IOSCHED_DEADLINE=y ++CONFIG_IOSCHED_DEADLINE=m + CONFIG_IOSCHED_CFQ=y +-# CONFIG_DEFAULT_AS is not set + # CONFIG_DEFAULT_DEADLINE is not set + CONFIG_DEFAULT_CFQ=y + # CONFIG_DEFAULT_NOOP is not set + CONFIG_DEFAULT_IOSCHED="cfq" ++# CONFIG_INLINE_SPIN_TRYLOCK is not set ++# CONFIG_INLINE_SPIN_TRYLOCK_BH is not set ++# CONFIG_INLINE_SPIN_LOCK is not set ++# CONFIG_INLINE_SPIN_LOCK_BH is not set ++# CONFIG_INLINE_SPIN_LOCK_IRQ is not set ++# CONFIG_INLINE_SPIN_LOCK_IRQSAVE is not set ++# CONFIG_INLINE_SPIN_UNLOCK is not set ++# CONFIG_INLINE_SPIN_UNLOCK_BH is not set ++# CONFIG_INLINE_SPIN_UNLOCK_IRQ is not set ++# CONFIG_INLINE_SPIN_UNLOCK_IRQRESTORE is not set ++# CONFIG_INLINE_READ_TRYLOCK is not set ++# CONFIG_INLINE_READ_LOCK is not set ++# CONFIG_INLINE_READ_LOCK_BH is not set ++# CONFIG_INLINE_READ_LOCK_IRQ is not set ++# CONFIG_INLINE_READ_LOCK_IRQSAVE is not set ++# CONFIG_INLINE_READ_UNLOCK is not set ++# CONFIG_INLINE_READ_UNLOCK_BH is not set ++# CONFIG_INLINE_READ_UNLOCK_IRQ is not set ++# CONFIG_INLINE_READ_UNLOCK_IRQRESTORE is not set ++# CONFIG_INLINE_WRITE_TRYLOCK is not set ++# CONFIG_INLINE_WRITE_LOCK is not set ++# CONFIG_INLINE_WRITE_LOCK_BH is not set ++# CONFIG_INLINE_WRITE_LOCK_IRQ is not set ++# CONFIG_INLINE_WRITE_LOCK_IRQSAVE is not set ++# CONFIG_INLINE_WRITE_UNLOCK is not set ++# CONFIG_INLINE_WRITE_UNLOCK_BH is not set ++# CONFIG_INLINE_WRITE_UNLOCK_IRQ is not set ++# CONFIG_INLINE_WRITE_UNLOCK_IRQRESTORE is not set ++# CONFIG_MUTEX_SPIN_ON_OWNER is not set + CONFIG_FREEZER=y + + # +@@ -300,7 +331,7 @@ + CONFIG_PCI=y + CONFIG_PCI_DOMAINS=y + # CONFIG_ARCH_SUPPORTS_MSI is not set +-CONFIG_PCI_LEGACY=y ++# CONFIG_PCI_LEGACY is not set + # CONFIG_PCI_STUB is not set + # CONFIG_PCI_IOV is not set + CONFIG_ISA=y +@@ -314,7 +345,7 @@ + CONFIG_BINFMT_ELF=y + # CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS is not set + # CONFIG_HAVE_AOUT is not set +-# CONFIG_BINFMT_MISC is not set ++CONFIG_BINFMT_MISC=m + CONFIG_MIPS32_COMPAT=y + CONFIG_COMPAT=y + CONFIG_SYSVIPC_COMPAT=y +@@ -335,7 +366,33 @@ + CONFIG_HIBERNATION_NVS=y + CONFIG_HIBERNATION=y + CONFIG_PM_STD_PARTITION="/dev/hda3" +-# CONFIG_PM_RUNTIME is not set ++CONFIG_PM_RUNTIME=y ++CONFIG_MIPS_EXTERNAL_TIMER=y ++CONFIG_MIPS_CPUFREQ=y ++ ++# ++# CPU Frequency scaling ++# ++CONFIG_CPU_FREQ=y ++CONFIG_CPU_FREQ_TABLE=y ++CONFIG_CPU_FREQ_DEBUG=y ++CONFIG_CPU_FREQ_STAT=m ++CONFIG_CPU_FREQ_STAT_DETAILS=y ++# CONFIG_CPU_FREQ_DEFAULT_GOV_PERFORMANCE is not set ++# CONFIG_CPU_FREQ_DEFAULT_GOV_POWERSAVE is not set ++# CONFIG_CPU_FREQ_DEFAULT_GOV_USERSPACE is not set ++CONFIG_CPU_FREQ_DEFAULT_GOV_ONDEMAND=y ++# CONFIG_CPU_FREQ_DEFAULT_GOV_CONSERVATIVE is not set ++CONFIG_CPU_FREQ_GOV_PERFORMANCE=y ++CONFIG_CPU_FREQ_GOV_POWERSAVE=m ++CONFIG_CPU_FREQ_GOV_USERSPACE=m ++CONFIG_CPU_FREQ_GOV_ONDEMAND=y ++CONFIG_CPU_FREQ_GOV_CONSERVATIVE=m ++ ++# ++# CPUFreq processor drivers ++# ++CONFIG_LOONGSON2_CPUFREQ=m + CONFIG_NET=y + CONFIG_COMPAT_NETLINK_MESSAGES=y + +@@ -346,11 +403,12 @@ + CONFIG_PACKET_MMAP=y + CONFIG_UNIX=y + CONFIG_XFRM=y +-# CONFIG_XFRM_USER is not set ++CONFIG_XFRM_USER=m + # CONFIG_XFRM_SUB_POLICY is not set + # CONFIG_XFRM_MIGRATE is not set + # CONFIG_XFRM_STATISTICS is not set +-# CONFIG_NET_KEY is not set ++CONFIG_NET_KEY=m ++# CONFIG_NET_KEY_MIGRATE is not set + CONFIG_INET=y + CONFIG_IP_MULTICAST=y + CONFIG_IP_ADVANCED_ROUTER=y +@@ -361,12 +419,13 @@ + CONFIG_IP_ROUTE_MULTIPATH=y + CONFIG_IP_ROUTE_VERBOSE=y + # CONFIG_IP_PNP is not set +-# CONFIG_NET_IPIP is not set +-# CONFIG_NET_IPGRE is not set ++CONFIG_NET_IPIP=m ++CONFIG_NET_IPGRE=m ++# CONFIG_NET_IPGRE_BROADCAST is not set + CONFIG_IP_MROUTE=y + CONFIG_IP_PIMSM_V1=y + CONFIG_IP_PIMSM_V2=y +-# CONFIG_ARPD is not set ++CONFIG_ARPD=y + CONFIG_SYN_COOKIES=y + # CONFIG_INET_AH is not set + # CONFIG_INET_ESP is not set +@@ -399,30 +458,34 @@ + # CONFIG_DEFAULT_WESTWOOD is not set + # CONFIG_DEFAULT_RENO is not set + CONFIG_DEFAULT_TCP_CONG="bic" +-# CONFIG_TCP_MD5SIG is not set ++CONFIG_TCP_MD5SIG=y + CONFIG_IPV6=m + CONFIG_IPV6_PRIVACY=y +-# CONFIG_IPV6_ROUTER_PREF is not set ++CONFIG_IPV6_ROUTER_PREF=y ++# CONFIG_IPV6_ROUTE_INFO is not set + # CONFIG_IPV6_OPTIMISTIC_DAD is not set + # CONFIG_INET6_AH is not set + # CONFIG_INET6_ESP is not set + # CONFIG_INET6_IPCOMP is not set + # CONFIG_IPV6_MIP6 is not set + # CONFIG_INET6_XFRM_TUNNEL is not set +-# CONFIG_INET6_TUNNEL is not set ++CONFIG_INET6_TUNNEL=m + CONFIG_INET6_XFRM_MODE_TRANSPORT=m + CONFIG_INET6_XFRM_MODE_TUNNEL=m + CONFIG_INET6_XFRM_MODE_BEET=m + # CONFIG_INET6_XFRM_MODE_ROUTEOPTIMIZATION is not set + CONFIG_IPV6_SIT=m ++# CONFIG_IPV6_SIT_6RD is not set + CONFIG_IPV6_NDISC_NODETYPE=y +-# CONFIG_IPV6_TUNNEL is not set +-# CONFIG_IPV6_MULTIPLE_TABLES is not set ++CONFIG_IPV6_TUNNEL=m ++CONFIG_IPV6_MULTIPLE_TABLES=y ++CONFIG_IPV6_SUBTREES=y + # CONFIG_IPV6_MROUTE is not set + CONFIG_NETWORK_SECMARK=y + CONFIG_NETFILTER=y + # CONFIG_NETFILTER_DEBUG is not set + CONFIG_NETFILTER_ADVANCED=y ++CONFIG_BRIDGE_NETFILTER=y + + # + # Core Netfilter Configuration +@@ -446,17 +509,22 @@ + # + # CONFIG_IP6_NF_QUEUE is not set + # CONFIG_IP6_NF_IPTABLES is not set ++# CONFIG_BRIDGE_NF_EBTABLES is not set + # CONFIG_IP_DCCP is not set + # CONFIG_IP_SCTP is not set + # CONFIG_RDS is not set + # CONFIG_TIPC is not set + # CONFIG_ATM is not set +-# CONFIG_BRIDGE is not set ++CONFIG_STP=m ++CONFIG_BRIDGE=m + # CONFIG_NET_DSA is not set +-# CONFIG_VLAN_8021Q is not set ++CONFIG_VLAN_8021Q=m ++# CONFIG_VLAN_8021Q_GVRP is not set + # CONFIG_DECNET is not set ++CONFIG_LLC=m + # CONFIG_LLC2 is not set +-# CONFIG_IPX is not set ++CONFIG_IPX=m ++# CONFIG_IPX_INTERN is not set + # CONFIG_ATALK is not set + # CONFIG_X25 is not set + # CONFIG_LAPB is not set +@@ -518,26 +586,64 @@ + # Network testing + # + # CONFIG_NET_PKTGEN is not set ++# CONFIG_NET_DROP_MONITOR is not set + # CONFIG_HAMRADIO is not set + # CONFIG_CAN is not set + # CONFIG_IRDA is not set +-# CONFIG_BT is not set ++CONFIG_BT=m ++CONFIG_BT_L2CAP=m ++CONFIG_BT_SCO=m ++CONFIG_BT_RFCOMM=m ++CONFIG_BT_RFCOMM_TTY=y ++CONFIG_BT_BNEP=m ++CONFIG_BT_BNEP_MC_FILTER=y ++CONFIG_BT_BNEP_PROTO_FILTER=y ++CONFIG_BT_HIDP=m ++ ++# ++# Bluetooth device drivers ++# ++CONFIG_BT_HCIBTUSB=m ++# CONFIG_BT_HCIBTSDIO is not set ++# CONFIG_BT_HCIUART is not set ++# CONFIG_BT_HCIBCM203X is not set ++# CONFIG_BT_HCIBPA10X is not set ++CONFIG_BT_HCIBFUSB=m ++CONFIG_BT_HCIVHCI=m ++# CONFIG_BT_MRVL is not set ++# CONFIG_BT_ATH3K is not set + # CONFIG_AF_RXRPC is not set + CONFIG_FIB_RULES=y + CONFIG_WIRELESS=y +-# CONFIG_CFG80211 is not set +-CONFIG_CFG80211_DEFAULT_PS_VALUE=0 +-# CONFIG_WIRELESS_OLD_REGULATORY is not set + CONFIG_WIRELESS_EXT=y ++CONFIG_WEXT_CORE=y ++CONFIG_WEXT_PROC=y ++CONFIG_WEXT_PRIV=y ++CONFIG_CFG80211=m ++# CONFIG_NL80211_TESTMODE is not set ++# CONFIG_CFG80211_DEVELOPER_WARNINGS is not set ++# CONFIG_CFG80211_REG_DEBUG is not set ++CONFIG_CFG80211_DEFAULT_PS=y ++# CONFIG_CFG80211_DEBUGFS is not set ++# CONFIG_WIRELESS_OLD_REGULATORY is not set ++CONFIG_CFG80211_WEXT=y + CONFIG_WIRELESS_EXT_SYSFS=y +-# CONFIG_LIB80211 is not set +- +-# +-# CFG80211 needs to be enabled for MAC80211 +-# ++CONFIG_LIB80211=m ++CONFIG_LIB80211_DEBUG=y ++CONFIG_MAC80211=m ++# CONFIG_MAC80211_RC_PID is not set ++CONFIG_MAC80211_RC_MINSTREL=y ++# CONFIG_MAC80211_RC_DEFAULT_PID is not set ++CONFIG_MAC80211_RC_DEFAULT_MINSTREL=y ++CONFIG_MAC80211_RC_DEFAULT="minstrel" ++# CONFIG_MAC80211_MESH is not set ++CONFIG_MAC80211_LEDS=y ++# CONFIG_MAC80211_DEBUGFS is not set ++# CONFIG_MAC80211_DEBUG_MENU is not set + # CONFIG_WIMAX is not set + CONFIG_RFKILL=m +-# CONFIG_RFKILL_INPUT is not set ++CONFIG_RFKILL_LEDS=y ++CONFIG_RFKILL_INPUT=y + # CONFIG_NET_9P is not set + + # +@@ -555,7 +661,7 @@ + CONFIG_FIRMWARE_IN_KERNEL=y + CONFIG_EXTRA_FIRMWARE="" + # CONFIG_SYS_HYPERVISOR is not set +-# CONFIG_CONNECTOR is not set ++CONFIG_CONNECTOR=m + # CONFIG_MTD is not set + # CONFIG_PARPORT is not set + # CONFIG_PNP is not set +@@ -566,7 +672,8 @@ + # CONFIG_BLK_DEV_UMEM is not set + # CONFIG_BLK_DEV_COW_COMMON is not set + CONFIG_BLK_DEV_LOOP=y +-CONFIG_BLK_DEV_CRYPTOLOOP=y ++CONFIG_BLK_DEV_CRYPTOLOOP=m ++# CONFIG_BLK_DEV_DRBD is not set + # CONFIG_BLK_DEV_NBD is not set + # CONFIG_BLK_DEV_SX8 is not set + # CONFIG_BLK_DEV_UB is not set +@@ -577,19 +684,7 @@ + # CONFIG_CDROM_PKTCDVD is not set + # CONFIG_ATA_OVER_ETH is not set + # CONFIG_BLK_DEV_HD is not set +-CONFIG_MISC_DEVICES=y +-# CONFIG_PHANTOM is not set +-# CONFIG_SGI_IOC4 is not set +-# CONFIG_TIFM_CORE is not set +-# CONFIG_ENCLOSURE_SERVICES is not set +-# CONFIG_HP_ILO is not set +-# CONFIG_C2PORT is not set +- +-# +-# EEPROM support +-# +-# CONFIG_EEPROM_93CX6 is not set +-# CONFIG_CB710_CORE is not set ++# CONFIG_MISC_DEVICES is not set + CONFIG_HAVE_IDE=y + CONFIG_IDE=y + +@@ -619,8 +714,7 @@ + # + CONFIG_BLK_DEV_IDEPCI=y + # CONFIG_IDEPCI_PCIBUS_ORDER is not set +-# CONFIG_BLK_DEV_OFFBOARD is not set +-CONFIG_BLK_DEV_GENERIC=y ++# CONFIG_BLK_DEV_GENERIC is not set + # CONFIG_BLK_DEV_OPTI621 is not set + CONFIG_BLK_DEV_IDEDMA_PCI=y + # CONFIG_BLK_DEV_AEC62XX is not set +@@ -700,7 +794,29 @@ + # CONFIG_SCSI_DH is not set + # CONFIG_SCSI_OSD_INITIATOR is not set + # CONFIG_ATA is not set +-# CONFIG_MD is not set ++CONFIG_MD=y ++CONFIG_BLK_DEV_MD=m ++CONFIG_MD_LINEAR=m ++CONFIG_MD_RAID0=m ++CONFIG_MD_RAID1=m ++CONFIG_MD_RAID10=m ++CONFIG_MD_RAID456=m ++CONFIG_MD_RAID6_PQ=m ++# CONFIG_ASYNC_RAID6_TEST is not set ++CONFIG_MD_MULTIPATH=m ++CONFIG_MD_FAULTY=m ++CONFIG_BLK_DEV_DM=m ++CONFIG_DM_DEBUG=y ++CONFIG_DM_CRYPT=m ++CONFIG_DM_SNAPSHOT=m ++CONFIG_DM_MIRROR=m ++CONFIG_DM_LOG_USERSPACE=m ++CONFIG_DM_ZERO=m ++CONFIG_DM_MULTIPATH=m ++CONFIG_DM_MULTIPATH_QL=m ++CONFIG_DM_MULTIPATH_ST=m ++CONFIG_DM_DELAY=m ++CONFIG_DM_UEVENT=y + # CONFIG_FUSION is not set + + # +@@ -712,19 +828,19 @@ + # + + # +-# See the help texts for more information. ++# The newer stack is recommended. + # + # CONFIG_FIREWIRE is not set + # CONFIG_IEEE1394 is not set + # CONFIG_I2O is not set + CONFIG_NETDEVICES=y + # CONFIG_IFB is not set +-# CONFIG_DUMMY is not set ++CONFIG_DUMMY=m + # CONFIG_BONDING is not set + # CONFIG_MACVLAN is not set + # CONFIG_EQUALIZER is not set +-# CONFIG_TUN is not set +-# CONFIG_VETH is not set ++CONFIG_TUN=m ++CONFIG_VETH=m + # CONFIG_ARCNET is not set + # CONFIG_PHYLIB is not set + CONFIG_NET_ETHERNET=y +@@ -738,6 +854,7 @@ + # CONFIG_SMC91X is not set + # CONFIG_DM9000 is not set + # CONFIG_ETHOC is not set ++# CONFIG_SMSC911X is not set + # CONFIG_NET_VENDOR_RACAL is not set + # CONFIG_DNET is not set + # CONFIG_NET_TULIP is not set +@@ -767,9 +884,9 @@ + # CONFIG_NATSEMI is not set + # CONFIG_NE2K_PCI is not set + # CONFIG_8139CP is not set +-CONFIG_8139TOO=y ++CONFIG_8139TOO=m + # CONFIG_8139TOO_PIO is not set +-CONFIG_8139TOO_TUNE_TWISTER=y ++# CONFIG_8139TOO_TUNE_TWISTER is not set + # CONFIG_8139TOO_8129 is not set + # CONFIG_8139_OLD_RX_RESET is not set + # CONFIG_R6040 is not set +@@ -794,7 +911,8 @@ + # CONFIG_NS83820 is not set + # CONFIG_HAMACHI is not set + # CONFIG_YELLOWFIN is not set +-CONFIG_R8169=y ++CONFIG_R8169=m ++CONFIG_R8169_VLAN=y + # CONFIG_SIS190 is not set + # CONFIG_SKGE is not set + # CONFIG_SKY2 is not set +@@ -810,15 +928,31 @@ + # CONFIG_NETDEV_10000 is not set + # CONFIG_TR is not set + CONFIG_WLAN=y +-CONFIG_WLAN_PRE80211=y +-# CONFIG_STRIP is not set +-# CONFIG_WAVELAN is not set +-CONFIG_WLAN_80211=y +-# CONFIG_LIBERTAS is not set ++# CONFIG_LIBERTAS_THINFIRM is not set + # CONFIG_ATMEL is not set ++# CONFIG_AT76C50X_USB is not set + # CONFIG_PRISM54 is not set + # CONFIG_USB_ZD1201 is not set ++# CONFIG_USB_NET_RNDIS_WLAN is not set ++# CONFIG_RTL8180 is not set ++CONFIG_RTL8187B=m ++# CONFIG_ADM8211 is not set ++# CONFIG_MAC80211_HWSIM is not set ++# CONFIG_MWL8K is not set ++# CONFIG_ATH_COMMON is not set ++# CONFIG_B43 is not set ++# CONFIG_B43LEGACY is not set + # CONFIG_HOSTAP is not set ++# CONFIG_IPW2100 is not set ++# CONFIG_IPW2200 is not set ++# CONFIG_IWLWIFI is not set ++# CONFIG_IWM is not set ++# CONFIG_LIBERTAS is not set ++# CONFIG_HERMES is not set ++# CONFIG_P54_COMMON is not set ++# CONFIG_RT2X00 is not set ++# CONFIG_WL12XX is not set ++# CONFIG_ZD1211RW is not set + + # + # Enable WiMAX (Networking options) to see the WiMAX drivers +@@ -831,17 +965,39 @@ + # CONFIG_USB_KAWETH is not set + # CONFIG_USB_PEGASUS is not set + # CONFIG_USB_RTL8150 is not set +-# CONFIG_USB_USBNET is not set ++CONFIG_USB_USBNET=m ++CONFIG_USB_NET_AX8817X=m ++CONFIG_USB_NET_CDCETHER=m ++CONFIG_USB_NET_CDC_EEM=m ++# CONFIG_USB_NET_DM9601 is not set ++# CONFIG_USB_NET_SMSC95XX is not set ++# CONFIG_USB_NET_GL620A is not set ++CONFIG_USB_NET_NET1080=m ++# CONFIG_USB_NET_PLUSB is not set ++# CONFIG_USB_NET_MCS7830 is not set ++# CONFIG_USB_NET_RNDIS_HOST is not set ++CONFIG_USB_NET_CDC_SUBSET=m ++# CONFIG_USB_ALI_M5632 is not set ++# CONFIG_USB_AN2720 is not set ++CONFIG_USB_BELKIN=y ++CONFIG_USB_ARMLINUX=y ++# CONFIG_USB_EPSON2888 is not set ++# CONFIG_USB_KC2190 is not set ++CONFIG_USB_NET_ZAURUS=m + # CONFIG_USB_HSO is not set ++# CONFIG_USB_NET_INT51X1 is not set + # CONFIG_WAN is not set + # CONFIG_FDDI is not set + # CONFIG_HIPPI is not set + # CONFIG_PPP is not set + # CONFIG_SLIP is not set + # CONFIG_NET_FC is not set +-# CONFIG_NETCONSOLE is not set +-# CONFIG_NETPOLL is not set +-# CONFIG_NET_POLL_CONTROLLER is not set ++CONFIG_NETCONSOLE=m ++CONFIG_NETCONSOLE_DYNAMIC=y ++CONFIG_NETPOLL=y ++# CONFIG_NETPOLL_TRAP is not set ++CONFIG_NET_POLL_CONTROLLER=y ++# CONFIG_VMXNET3 is not set + # CONFIG_ISDN is not set + # CONFIG_PHONE is not set + +@@ -849,25 +1005,26 @@ + # Input device support + # + CONFIG_INPUT=y +-# CONFIG_INPUT_FF_MEMLESS is not set +-# CONFIG_INPUT_POLLDEV is not set ++CONFIG_INPUT_FF_MEMLESS=m ++CONFIG_INPUT_POLLDEV=m ++CONFIG_INPUT_SPARSEKMAP=m + + # + # Userland interfaces + # +-CONFIG_INPUT_MOUSEDEV=y ++CONFIG_INPUT_MOUSEDEV=m + CONFIG_INPUT_MOUSEDEV_PSAUX=y + CONFIG_INPUT_MOUSEDEV_SCREEN_X=1024 + CONFIG_INPUT_MOUSEDEV_SCREEN_Y=768 + # CONFIG_INPUT_JOYDEV is not set +-CONFIG_INPUT_EVDEV=y ++CONFIG_INPUT_EVDEV=m + # CONFIG_INPUT_EVBUG is not set + + # + # Input Device Drivers + # + CONFIG_INPUT_KEYBOARD=y +-CONFIG_KEYBOARD_ATKBD=y ++CONFIG_KEYBOARD_ATKBD=m + # CONFIG_KEYBOARD_LKKBD is not set + # CONFIG_KEYBOARD_NEWTON is not set + # CONFIG_KEYBOARD_OPENCORES is not set +@@ -875,7 +1032,7 @@ + # CONFIG_KEYBOARD_SUNKBD is not set + # CONFIG_KEYBOARD_XTKBD is not set + CONFIG_INPUT_MOUSE=y +-CONFIG_MOUSE_PS2=y ++CONFIG_MOUSE_PS2=m + # CONFIG_MOUSE_PS2_ALPS is not set + # CONFIG_MOUSE_PS2_LOGIPS2PP is not set + CONFIG_MOUSE_PS2_SYNAPTICS=y +@@ -884,7 +1041,7 @@ + # CONFIG_MOUSE_PS2_SENTELIC is not set + # CONFIG_MOUSE_PS2_TOUCHKIT is not set + # CONFIG_MOUSE_SERIAL is not set +-# CONFIG_MOUSE_APPLETOUCH is not set ++CONFIG_MOUSE_APPLETOUCH=m + # CONFIG_MOUSE_BCM5974 is not set + # CONFIG_MOUSE_INPORT is not set + # CONFIG_MOUSE_LOGIBM is not set +@@ -904,6 +1061,7 @@ + # CONFIG_SERIO_PCIPS2 is not set + CONFIG_SERIO_LIBPS2=y + # CONFIG_SERIO_RAW is not set ++# CONFIG_SERIO_ALTERA_PS2 is not set + # CONFIG_GAMEPORT is not set + + # +@@ -915,27 +1073,13 @@ + CONFIG_HW_CONSOLE=y + # CONFIG_VT_HW_CONSOLE_BINDING is not set + CONFIG_DEVKMEM=y +-CONFIG_SERIAL_NONSTANDARD=y +-# CONFIG_COMPUTONE is not set +-# CONFIG_ROCKETPORT is not set +-# CONFIG_CYCLADES is not set +-# CONFIG_DIGIEPCA is not set +-# CONFIG_MOXA_INTELLIO is not set +-# CONFIG_MOXA_SMARTIO is not set +-# CONFIG_ISI is not set +-# CONFIG_SYNCLINKMP is not set +-# CONFIG_SYNCLINK_GT is not set +-# CONFIG_N_HDLC is not set +-# CONFIG_RISCOM8 is not set +-# CONFIG_SPECIALIX is not set +-# CONFIG_STALDRV is not set ++# CONFIG_SERIAL_NONSTANDARD is not set + # CONFIG_NOZOMI is not set + + # + # Serial drivers + # +-CONFIG_SERIAL_8250=y +-CONFIG_SERIAL_8250_CONSOLE=y ++CONFIG_SERIAL_8250=m + # CONFIG_SERIAL_8250_PCI is not set + CONFIG_SERIAL_8250_NR_UARTS=16 + CONFIG_SERIAL_8250_RUNTIME_UARTS=4 +@@ -953,8 +1097,7 @@ + # + # Non-8250 serial port support + # +-CONFIG_SERIAL_CORE=y +-CONFIG_SERIAL_CORE_CONSOLE=y ++CONFIG_SERIAL_CORE=m + # CONFIG_SERIAL_JSM is not set + CONFIG_UNIX98_PTYS=y + # CONFIG_DEVPTS_MULTIPLE_INSTANCES is not set +@@ -963,7 +1106,6 @@ + # CONFIG_IPMI_HANDLER is not set + CONFIG_HW_RANDOM=y + # CONFIG_HW_RANDOM_TIMERIOMEM is not set +-CONFIG_RTC=y + # CONFIG_DTLK is not set + # CONFIG_R3964 is not set + # CONFIG_APPLICOM is not set +@@ -978,7 +1120,10 @@ + # + # CONFIG_PPS is not set + # CONFIG_W1 is not set +-# CONFIG_POWER_SUPPLY is not set ++CONFIG_POWER_SUPPLY=m ++# CONFIG_POWER_SUPPLY_DEBUG is not set ++# CONFIG_PDA_POWER is not set ++# CONFIG_BATTERY_DS2760 is not set + CONFIG_HWMON=y + # CONFIG_HWMON_VID is not set + # CONFIG_HWMON_DEBUG_CHIP is not set +@@ -1033,14 +1178,18 @@ + # + # Multimedia drivers + # ++CONFIG_IR_CORE=m ++CONFIG_VIDEO_IR=m + # CONFIG_MEDIA_ATTACH is not set + CONFIG_VIDEO_V4L2=m + CONFIG_VIDEO_V4L1=m ++CONFIG_VIDEOBUF_GEN=m ++CONFIG_VIDEOBUF_VMALLOC=m + CONFIG_VIDEO_CAPTURE_DRIVERS=y + # CONFIG_VIDEO_ADV_DEBUG is not set + # CONFIG_VIDEO_FIXED_MINOR_RANGES is not set + CONFIG_VIDEO_HELPER_CHIPS_AUTO=y +-# CONFIG_VIDEO_VIVI is not set ++CONFIG_VIDEO_VIVI=m + # CONFIG_VIDEO_PMS is not set + # CONFIG_VIDEO_CPIA is not set + # CONFIG_VIDEO_CPIA2 is not set +@@ -1049,52 +1198,55 @@ + CONFIG_USB_VIDEO_CLASS=m + CONFIG_USB_VIDEO_CLASS_INPUT_EVDEV=y + CONFIG_USB_GSPCA=m +-# CONFIG_USB_M5602 is not set +-# CONFIG_USB_STV06XX is not set ++CONFIG_USB_M5602=m ++CONFIG_USB_STV06XX=m + # CONFIG_USB_GL860 is not set +-# CONFIG_USB_GSPCA_CONEX is not set +-# CONFIG_USB_GSPCA_ETOMS is not set +-# CONFIG_USB_GSPCA_FINEPIX is not set ++CONFIG_USB_GSPCA_CONEX=m ++CONFIG_USB_GSPCA_ETOMS=m ++CONFIG_USB_GSPCA_FINEPIX=m + # CONFIG_USB_GSPCA_JEILINJ is not set +-# CONFIG_USB_GSPCA_MARS is not set +-# CONFIG_USB_GSPCA_MR97310A is not set +-# CONFIG_USB_GSPCA_OV519 is not set +-# CONFIG_USB_GSPCA_OV534 is not set +-# CONFIG_USB_GSPCA_PAC207 is not set +-# CONFIG_USB_GSPCA_PAC7311 is not set +-# CONFIG_USB_GSPCA_SN9C20X is not set +-# CONFIG_USB_GSPCA_SONIXB is not set +-# CONFIG_USB_GSPCA_SONIXJ is not set +-# CONFIG_USB_GSPCA_SPCA500 is not set +-# CONFIG_USB_GSPCA_SPCA501 is not set +-# CONFIG_USB_GSPCA_SPCA505 is not set +-# CONFIG_USB_GSPCA_SPCA506 is not set +-# CONFIG_USB_GSPCA_SPCA508 is not set +-# CONFIG_USB_GSPCA_SPCA561 is not set +-# CONFIG_USB_GSPCA_SQ905 is not set +-# CONFIG_USB_GSPCA_SQ905C is not set +-# CONFIG_USB_GSPCA_STK014 is not set +-# CONFIG_USB_GSPCA_SUNPLUS is not set +-# CONFIG_USB_GSPCA_T613 is not set +-# CONFIG_USB_GSPCA_TV8532 is not set +-# CONFIG_USB_GSPCA_VC032X is not set +-# CONFIG_USB_GSPCA_ZC3XX is not set ++CONFIG_USB_GSPCA_MARS=m ++CONFIG_USB_GSPCA_MR97310A=m ++CONFIG_USB_GSPCA_OV519=m ++CONFIG_USB_GSPCA_OV534=m ++CONFIG_USB_GSPCA_PAC207=m ++# CONFIG_USB_GSPCA_PAC7302 is not set ++CONFIG_USB_GSPCA_PAC7311=m ++CONFIG_USB_GSPCA_SN9C20X=m ++CONFIG_USB_GSPCA_SN9C20X_EVDEV=y ++CONFIG_USB_GSPCA_SONIXB=m ++CONFIG_USB_GSPCA_SONIXJ=m ++CONFIG_USB_GSPCA_SPCA500=m ++CONFIG_USB_GSPCA_SPCA501=m ++CONFIG_USB_GSPCA_SPCA505=m ++CONFIG_USB_GSPCA_SPCA506=m ++CONFIG_USB_GSPCA_SPCA508=m ++CONFIG_USB_GSPCA_SPCA561=m ++CONFIG_USB_GSPCA_SQ905=m ++CONFIG_USB_GSPCA_SQ905C=m ++CONFIG_USB_GSPCA_STK014=m ++# CONFIG_USB_GSPCA_STV0680 is not set ++CONFIG_USB_GSPCA_SUNPLUS=m ++CONFIG_USB_GSPCA_T613=m ++CONFIG_USB_GSPCA_TV8532=m ++CONFIG_USB_GSPCA_VC032X=m ++CONFIG_USB_GSPCA_ZC3XX=m + # CONFIG_VIDEO_HDPVR is not set + # CONFIG_USB_VICAM is not set + # CONFIG_USB_IBMCAM is not set + # CONFIG_USB_KONICAWC is not set + # CONFIG_USB_QUICKCAM_MESSENGER is not set +-# CONFIG_USB_ET61X251 is not set ++CONFIG_USB_ET61X251=m + # CONFIG_USB_OV511 is not set + # CONFIG_USB_SE401 is not set +-# CONFIG_USB_SN9C102 is not set ++CONFIG_USB_SN9C102=m + # CONFIG_USB_STV680 is not set +-# CONFIG_USB_ZC0301 is not set ++CONFIG_USB_ZC0301=m + # CONFIG_USB_PWC is not set + CONFIG_USB_PWC_INPUT_EVDEV=y +-# CONFIG_USB_ZR364XX is not set +-# CONFIG_USB_STKWEBCAM is not set +-# CONFIG_USB_S2255 is not set ++CONFIG_USB_ZR364XX=m ++CONFIG_USB_STKWEBCAM=m ++CONFIG_USB_S2255=m + # CONFIG_RADIO_ADAPTERS is not set + # CONFIG_DAB is not set + +@@ -1132,6 +1284,7 @@ + # CONFIG_FB_CYBER2000 is not set + # CONFIG_FB_ASILIANT is not set + # CONFIG_FB_IMSTT is not set ++# CONFIG_FB_UVESA is not set + # CONFIG_FB_S1D13XXX is not set + # CONFIG_FB_NVIDIA is not set + # CONFIG_FB_RIVA is not set +@@ -1161,7 +1314,7 @@ + CONFIG_BACKLIGHT_LCD_SUPPORT=y + # CONFIG_LCD_CLASS_DEVICE is not set + CONFIG_BACKLIGHT_CLASS_DEVICE=y +-CONFIG_BACKLIGHT_GENERIC=y ++CONFIG_BACKLIGHT_GENERIC=m + + # + # Display device support +@@ -1188,33 +1341,45 @@ + CONFIG_FONT_SUN8x16=y + CONFIG_FONT_SUN12x22=y + CONFIG_FONT_10x18=y +-CONFIG_LOGO=y +-# CONFIG_LOGO_LINUX_MONO is not set +-# CONFIG_LOGO_LINUX_VGA16 is not set +-CONFIG_LOGO_LINUX_CLUT224=y ++# CONFIG_LOGO is not set + CONFIG_SOUND=m +-# CONFIG_SOUND_OSS_CORE is not set ++CONFIG_SOUND_OSS_CORE=y ++CONFIG_SOUND_OSS_CORE_PRECLAIM=y + 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_HRTIMER is not set +-# CONFIG_SND_RTCTIMER is not set ++CONFIG_SND_HWDEP=m ++CONFIG_SND_RAWMIDI=m ++CONFIG_SND_SEQUENCER=m ++CONFIG_SND_SEQ_DUMMY=m ++CONFIG_SND_OSSEMUL=y ++CONFIG_SND_MIXER_OSS=m ++CONFIG_SND_PCM_OSS=m ++CONFIG_SND_PCM_OSS_PLUGINS=y ++CONFIG_SND_SEQUENCER_OSS=y ++CONFIG_SND_HRTIMER=m ++CONFIG_SND_SEQ_HRTIMER_DEFAULT=y + # CONFIG_SND_DYNAMIC_MINORS is not set +-# CONFIG_SND_SUPPORT_OLD_API is not set +-# CONFIG_SND_VERBOSE_PROCFS is not set ++CONFIG_SND_SUPPORT_OLD_API=y ++CONFIG_SND_VERBOSE_PROCFS=y + # CONFIG_SND_VERBOSE_PRINTK is not set + # CONFIG_SND_DEBUG is not set + CONFIG_SND_VMASTER=y +-# CONFIG_SND_RAWMIDI_SEQ is not set ++CONFIG_SND_RAWMIDI_SEQ=m + # CONFIG_SND_OPL3_LIB_SEQ is not set + # CONFIG_SND_OPL4_LIB_SEQ is not set + # CONFIG_SND_SBAWE_SEQ is not set + # CONFIG_SND_EMU10K1_SEQ is not set ++CONFIG_SND_MPU401_UART=m + CONFIG_SND_AC97_CODEC=m +-# CONFIG_SND_DRIVERS is not set ++CONFIG_SND_DRIVERS=y ++CONFIG_SND_DUMMY=m ++CONFIG_SND_VIRMIDI=m ++# CONFIG_SND_MTPAV is not set ++CONFIG_SND_SERIAL_U16550=m ++CONFIG_SND_MPU401=m ++CONFIG_SND_AC97_POWER_SAVE=y ++CONFIG_SND_AC97_POWER_SAVE_DEFAULT=10 + CONFIG_SND_PCI=y + # CONFIG_SND_AD1889 is not set + # CONFIG_SND_ALS300 is not set +@@ -1281,7 +1446,10 @@ + # CONFIG_SND_VX222 is not set + # CONFIG_SND_YMFPCI is not set + # CONFIG_SND_MIPS is not set +-# CONFIG_SND_USB is not set ++CONFIG_SND_USB=y ++CONFIG_SND_USB_AUDIO=m ++CONFIG_SND_USB_CAIAQ=m ++CONFIG_SND_USB_CAIAQ_INPUT=y + # CONFIG_SND_SOC is not set + # CONFIG_SOUND_PRIME is not set + CONFIG_AC97_BUS=m +@@ -1299,32 +1467,41 @@ + # + # Special HID drivers + # +-# CONFIG_HID_A4TECH is not set +-# CONFIG_HID_APPLE is not set +-# CONFIG_HID_BELKIN is not set +-# CONFIG_HID_CHERRY is not set +-# CONFIG_HID_CHICONY is not set +-# CONFIG_HID_CYPRESS is not set +-# CONFIG_HID_DRAGONRISE is not set +-# CONFIG_HID_EZKEY is not set +-# CONFIG_HID_KYE is not set +-# CONFIG_HID_GYRATION is not set +-# CONFIG_HID_TWINHAN is not set +-# CONFIG_HID_KENSINGTON is not set +-# CONFIG_HID_LOGITECH is not set +-# CONFIG_HID_MICROSOFT is not set +-# CONFIG_HID_MONTEREY is not set +-# CONFIG_HID_NTRIG is not set +-# CONFIG_HID_PANTHERLORD is not set +-# CONFIG_HID_PETALYNX is not set +-# CONFIG_HID_SAMSUNG is not set +-# CONFIG_HID_SONY is not set +-# CONFIG_HID_SUNPLUS is not set +-# CONFIG_HID_GREENASIA is not set +-# CONFIG_HID_SMARTJOYPLUS is not set +-# CONFIG_HID_TOPSEED is not set +-# CONFIG_HID_THRUSTMASTER is not set +-# CONFIG_HID_ZEROPLUS is not set ++CONFIG_HID_A4TECH=m ++CONFIG_HID_APPLE=m ++CONFIG_HID_BELKIN=m ++CONFIG_HID_CHERRY=m ++CONFIG_HID_CHICONY=m ++CONFIG_HID_CYPRESS=m ++CONFIG_HID_DRAGONRISE=m ++CONFIG_DRAGONRISE_FF=y ++CONFIG_HID_EZKEY=m ++CONFIG_HID_KYE=m ++CONFIG_HID_GYRATION=m ++CONFIG_HID_TWINHAN=m ++CONFIG_HID_KENSINGTON=m ++CONFIG_HID_LOGITECH=m ++CONFIG_LOGITECH_FF=y ++CONFIG_LOGIRUMBLEPAD2_FF=y ++CONFIG_HID_MICROSOFT=m ++CONFIG_HID_MONTEREY=m ++CONFIG_HID_NTRIG=m ++CONFIG_HID_PANTHERLORD=m ++CONFIG_PANTHERLORD_FF=y ++CONFIG_HID_PETALYNX=m ++CONFIG_HID_SAMSUNG=m ++CONFIG_HID_SONY=m ++CONFIG_HID_SUNPLUS=m ++CONFIG_HID_GREENASIA=m ++CONFIG_GREENASIA_FF=y ++CONFIG_HID_SMARTJOYPLUS=m ++CONFIG_SMARTJOYPLUS_FF=y ++CONFIG_HID_TOPSEED=m ++CONFIG_HID_THRUSTMASTER=m ++CONFIG_THRUSTMASTER_FF=y ++CONFIG_HID_WACOM=m ++CONFIG_HID_ZEROPLUS=m ++CONFIG_ZEROPLUS_FF=y + CONFIG_USB_SUPPORT=y + CONFIG_USB_ARCH_HAS_HCD=y + CONFIG_USB_ARCH_HAS_OHCI=y +@@ -1336,15 +1513,15 @@ + # + # Miscellaneous USB options + # +-CONFIG_USB_DEVICEFS=y ++# CONFIG_USB_DEVICEFS is not set + # CONFIG_USB_DEVICE_CLASS is not set + CONFIG_USB_DYNAMIC_MINORS=y + CONFIG_USB_SUSPEND=y + # CONFIG_USB_OTG is not set + CONFIG_USB_OTG_WHITELIST=y + # CONFIG_USB_OTG_BLACKLIST_HUB is not set +-CONFIG_USB_MON=y +-# CONFIG_USB_WUSB is not set ++CONFIG_USB_MON=m ++CONFIG_USB_WUSB=m + # CONFIG_USB_WUSB_CBAF is not set + + # +@@ -1366,14 +1543,15 @@ + CONFIG_USB_UHCI_HCD=m + # CONFIG_USB_SL811_HCD is not set + # CONFIG_USB_R8A66597_HCD is not set +-# CONFIG_USB_WHCI_HCD is not set +-# CONFIG_USB_HWA_HCD is not set ++CONFIG_USB_WHCI_HCD=m ++CONFIG_USB_HWA_HCD=m ++# CONFIG_USB_GADGET_MUSB_HDRC is not set + + # + # USB Device Class drivers + # + CONFIG_USB_ACM=m +-# CONFIG_USB_PRINTER is not set ++CONFIG_USB_PRINTER=m + CONFIG_USB_WDM=m + # CONFIG_USB_TMC is not set + +@@ -1397,7 +1575,7 @@ + # CONFIG_USB_STORAGE_ONETOUCH is not set + # CONFIG_USB_STORAGE_KARMA is not set + # CONFIG_USB_STORAGE_CYPRESS_ATACB is not set +-# CONFIG_USB_LIBUSUAL is not set ++CONFIG_USB_LIBUSUAL=y + + # + # USB Imaging devices +@@ -1467,7 +1645,7 @@ + # CONFIG_USB_LEGOTOWER is not set + # CONFIG_USB_LCD is not set + # CONFIG_USB_BERRY_CHARGE is not set +-# CONFIG_USB_LED is not set ++CONFIG_USB_LED=m + # CONFIG_USB_CYPRESS_CY7C63 is not set + # CONFIG_USB_CYTHERM is not set + # CONFIG_USB_IDMOUSE is not set +@@ -1480,19 +1658,136 @@ + # CONFIG_USB_TEST is not set + # CONFIG_USB_ISIGHTFW is not set + # CONFIG_USB_VST is not set +-# CONFIG_USB_GADGET is not set ++CONFIG_USB_GADGET=m ++# CONFIG_USB_GADGET_DEBUG_FILES is not set ++# CONFIG_USB_GADGET_DEBUG_FS is not set ++CONFIG_USB_GADGET_VBUS_DRAW=2 ++CONFIG_USB_GADGET_SELECTED=y ++# CONFIG_USB_GADGET_AT91 is not set ++# CONFIG_USB_GADGET_ATMEL_USBA is not set ++# CONFIG_USB_GADGET_FSL_USB2 is not set ++# CONFIG_USB_GADGET_LH7A40X is not set ++# CONFIG_USB_GADGET_OMAP is not set ++# CONFIG_USB_GADGET_PXA25X is not set ++# CONFIG_USB_GADGET_R8A66597 is not set ++# CONFIG_USB_GADGET_PXA27X is not set ++# CONFIG_USB_GADGET_S3C_HSOTG is not set ++# CONFIG_USB_GADGET_IMX is not set ++# CONFIG_USB_GADGET_S3C2410 is not set ++CONFIG_USB_GADGET_M66592=y ++CONFIG_USB_M66592=m ++# CONFIG_USB_GADGET_AMD5536UDC is not set ++# CONFIG_USB_GADGET_FSL_QE is not set ++# CONFIG_USB_GADGET_CI13XXX is not set ++# CONFIG_USB_GADGET_NET2280 is not set ++# CONFIG_USB_GADGET_GOKU is not set ++# CONFIG_USB_GADGET_LANGWELL is not set ++# CONFIG_USB_GADGET_DUMMY_HCD is not set ++CONFIG_USB_GADGET_DUALSPEED=y ++# CONFIG_USB_ZERO is not set ++# CONFIG_USB_AUDIO is not set ++# CONFIG_USB_ETH is not set ++# CONFIG_USB_GADGETFS is not set ++# CONFIG_USB_FILE_STORAGE is not set ++# CONFIG_USB_MASS_STORAGE is not set ++# CONFIG_USB_G_SERIAL is not set ++# CONFIG_USB_MIDI_GADGET is not set ++# CONFIG_USB_G_PRINTER is not set ++# CONFIG_USB_CDC_COMPOSITE is not set ++# CONFIG_USB_G_MULTI is not set + + # + # OTG and related infrastructure + # + # CONFIG_NOP_USB_XCEIV is not set +-# CONFIG_UWB is not set +-# CONFIG_MMC is not set ++CONFIG_UWB=m ++CONFIG_UWB_HWA=m ++CONFIG_UWB_WHCI=m ++# CONFIG_UWB_WLP is not set ++# CONFIG_UWB_I1480U is not set ++CONFIG_MMC=m ++# CONFIG_MMC_DEBUG is not set ++# CONFIG_MMC_UNSAFE_RESUME is not set ++ ++# ++# MMC/SD/SDIO Card Drivers ++# ++CONFIG_MMC_BLOCK=m ++CONFIG_MMC_BLOCK_BOUNCE=y ++# CONFIG_SDIO_UART is not set ++# CONFIG_MMC_TEST is not set ++ ++# ++# MMC/SD/SDIO Host Controller Drivers ++# ++# CONFIG_MMC_SDHCI is not set ++# CONFIG_MMC_AT91 is not set ++# CONFIG_MMC_ATMELMCI is not set ++# CONFIG_MMC_TIFM_SD is not set ++# CONFIG_MMC_CB710 is not set ++# CONFIG_MMC_VIA_SDMMC is not set + # CONFIG_MEMSTICK is not set +-# CONFIG_NEW_LEDS is not set ++CONFIG_NEW_LEDS=y ++CONFIG_LEDS_CLASS=m ++ ++# ++# LED drivers ++# ++ ++# ++# LED Triggers ++# ++CONFIG_LEDS_TRIGGERS=y ++# CONFIG_LEDS_TRIGGER_TIMER is not set ++# CONFIG_LEDS_TRIGGER_IDE_DISK is not set ++# CONFIG_LEDS_TRIGGER_HEARTBEAT is not set ++# CONFIG_LEDS_TRIGGER_BACKLIGHT is not set ++# CONFIG_LEDS_TRIGGER_DEFAULT_ON is not set ++ ++# ++# iptables trigger is under Netfilter config (LED target) ++# + # CONFIG_ACCESSIBILITY is not set + # CONFIG_INFINIBAND is not set +-# CONFIG_RTC_CLASS is not set ++CONFIG_RTC_LIB=y ++CONFIG_RTC_CLASS=y ++CONFIG_RTC_HCTOSYS=y ++CONFIG_RTC_HCTOSYS_DEVICE="rtc0" ++# CONFIG_RTC_DEBUG is not set ++ ++# ++# RTC interfaces ++# ++CONFIG_RTC_INTF_SYSFS=y ++CONFIG_RTC_INTF_PROC=y ++CONFIG_RTC_INTF_DEV=y ++# CONFIG_RTC_INTF_DEV_UIE_EMUL is not set ++# CONFIG_RTC_DRV_TEST is not set ++ ++# ++# SPI RTC drivers ++# ++ ++# ++# Platform RTC drivers ++# ++CONFIG_RTC_DRV_CMOS=y ++# CONFIG_RTC_DRV_DS1286 is not set ++# CONFIG_RTC_DRV_DS1511 is not set ++# CONFIG_RTC_DRV_DS1553 is not set ++# CONFIG_RTC_DRV_DS1742 is not set ++# CONFIG_RTC_DRV_STK17TA8 is not set ++# CONFIG_RTC_DRV_M48T86 is not set ++# CONFIG_RTC_DRV_M48T35 is not set ++# CONFIG_RTC_DRV_M48T59 is not set ++# CONFIG_RTC_DRV_MSM6242 is not set ++# CONFIG_RTC_DRV_BQ4802 is not set ++# CONFIG_RTC_DRV_RP5C01 is not set ++# CONFIG_RTC_DRV_V3020 is not set ++ ++# ++# on-CPU RTC drivers ++# + # CONFIG_DMADEVICES is not set + # CONFIG_AUXDISPLAY is not set + # CONFIG_UIO is not set +@@ -1504,22 +1799,21 @@ + # CONFIG_STAGING_EXCLUDE_BUILD is not set + # CONFIG_ET131X is not set + # CONFIG_USB_IP_COMMON is not set ++# CONFIG_W35UND is not set + # CONFIG_PRISM2_USB is not set + # CONFIG_ECHO is not set ++# CONFIG_OTUS is not set + # CONFIG_COMEDI is not set + # CONFIG_ASUS_OLED is not set + # CONFIG_ALTERA_PCIE_CHDMA is not set +-# CONFIG_RTL8187SE is not set ++# CONFIG_R8187SE is not set + # CONFIG_RTL8192SU is not set ++# CONFIG_RTL8192U is not set + # CONFIG_RTL8192E is not set + # CONFIG_INPUT_MIMIO is not set + # CONFIG_TRANZPORT is not set + + # +-# Android +-# +- +-# + # Qualcomm MSM Camera And Video + # + +@@ -1527,7 +1821,6 @@ + # Camera Sensor Selection + # + # CONFIG_INPUT_GPIO is not set +-# CONFIG_DST is not set + # CONFIG_POHMELFS is not set + # CONFIG_B3DFG is not set + # CONFIG_PLAN9AUTH is not set +@@ -1544,28 +1837,57 @@ + # + # CONFIG_RAR_REGISTER is not set + # CONFIG_IIO is not set ++# CONFIG_RAMZSWAP is not set ++# CONFIG_BATMAN_ADV is not set ++# CONFIG_STRIP is not set ++# CONFIG_WAVELAN is not set + CONFIG_FB_SM7XX=y +-CONFIG_FB_SM7XX_ACCEL=y ++CONFIG_MIPS_PLATFORM_DEVICES=y ++CONFIG_LEMOTE_YEELOONG2F=m ++CONFIG_LEMOTE_LYNLOONG2F=m + + # + # File systems + # +-# CONFIG_EXT2_FS is not set ++CONFIG_EXT2_FS=m ++# CONFIG_EXT2_FS_XATTR is not set ++# CONFIG_EXT2_FS_XIP is not set + CONFIG_EXT3_FS=y + # CONFIG_EXT3_DEFAULTS_TO_ORDERED is not set + CONFIG_EXT3_FS_XATTR=y + CONFIG_EXT3_FS_POSIX_ACL=y + CONFIG_EXT3_FS_SECURITY=y +-# CONFIG_EXT4_FS is not set ++CONFIG_EXT4_FS=y ++CONFIG_EXT4_FS_XATTR=y ++# CONFIG_EXT4_FS_POSIX_ACL is not set ++# CONFIG_EXT4_FS_SECURITY is not set ++# CONFIG_EXT4_DEBUG is not set + CONFIG_JBD=y ++# CONFIG_JBD_DEBUG is not set ++CONFIG_JBD2=y ++# CONFIG_JBD2_DEBUG is not set + CONFIG_FS_MBCACHE=y +-# CONFIG_REISERFS_FS is not set +-# CONFIG_JFS_FS is not set ++CONFIG_REISERFS_FS=m ++# CONFIG_REISERFS_CHECK is not set ++CONFIG_REISERFS_PROC_INFO=y ++CONFIG_REISERFS_FS_XATTR=y ++# CONFIG_REISERFS_FS_POSIX_ACL is not set ++# CONFIG_REISERFS_FS_SECURITY is not set ++CONFIG_JFS_FS=m ++CONFIG_JFS_POSIX_ACL=y ++# CONFIG_JFS_SECURITY is not set ++# CONFIG_JFS_DEBUG is not set ++# CONFIG_JFS_STATISTICS is not set + CONFIG_FS_POSIX_ACL=y +-# CONFIG_XFS_FS is not set ++CONFIG_XFS_FS=m ++CONFIG_XFS_QUOTA=y ++CONFIG_XFS_POSIX_ACL=y ++# CONFIG_XFS_RT is not set ++# CONFIG_XFS_DEBUG is not set + # CONFIG_GFS2_FS is not set + # CONFIG_OCFS2_FS is not set +-# CONFIG_BTRFS_FS is not set ++CONFIG_BTRFS_FS=m ++# CONFIG_BTRFS_FS_POSIX_ACL is not set + # CONFIG_NILFS2_FS is not set + CONFIG_FILE_LOCKING=y + CONFIG_FSNOTIFY=y +@@ -1575,17 +1897,26 @@ + CONFIG_QUOTA=y + # CONFIG_QUOTA_NETLINK_INTERFACE is not set + CONFIG_PRINT_QUOTA_WARNING=y ++CONFIG_QUOTA_TREE=m + # CONFIG_QFMT_V1 is not set +-# CONFIG_QFMT_V2 is not set ++CONFIG_QFMT_V2=m + CONFIG_QUOTACTL=y +-# CONFIG_AUTOFS_FS is not set +-# CONFIG_AUTOFS4_FS is not set +-# CONFIG_FUSE_FS is not set ++CONFIG_AUTOFS_FS=m ++CONFIG_AUTOFS4_FS=m ++CONFIG_FUSE_FS=m ++CONFIG_CUSE=m + + # + # Caches + # +-# CONFIG_FSCACHE is not set ++CONFIG_FSCACHE=m ++# CONFIG_FSCACHE_STATS is not set ++# CONFIG_FSCACHE_HISTOGRAM is not set ++# CONFIG_FSCACHE_DEBUG is not set ++# CONFIG_FSCACHE_OBJECT_LIST is not set ++CONFIG_CACHEFILES=m ++# CONFIG_CACHEFILES_DEBUG is not set ++# CONFIG_CACHEFILES_HISTOGRAM is not set + + # + # CD-ROM/DVD Filesystems +@@ -1599,11 +1930,13 @@ + # DOS/FAT/NT Filesystems + # + CONFIG_FAT_FS=m +-# CONFIG_MSDOS_FS is not set ++CONFIG_MSDOS_FS=m + CONFIG_VFAT_FS=m + CONFIG_FAT_DEFAULT_CODEPAGE=437 + CONFIG_FAT_DEFAULT_IOCHARSET="iso8859-1" +-# CONFIG_NTFS_FS is not set ++CONFIG_NTFS_FS=m ++# CONFIG_NTFS_DEBUG is not set ++CONFIG_NTFS_RW=y + + # + # Pseudo filesystems +@@ -1616,23 +1949,60 @@ + CONFIG_TMPFS=y + # CONFIG_TMPFS_POSIX_ACL is not set + # CONFIG_HUGETLB_PAGE is not set +-# CONFIG_CONFIGFS_FS is not set +-# CONFIG_MISC_FILESYSTEMS is not set ++CONFIG_CONFIGFS_FS=m ++CONFIG_MISC_FILESYSTEMS=y ++# CONFIG_ADFS_FS is not set ++# CONFIG_AFFS_FS is not set ++# CONFIG_ECRYPT_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_CRAMFS=m ++CONFIG_SQUASHFS=m ++CONFIG_SQUASHFS_EMBEDDED=y ++CONFIG_SQUASHFS_FRAGMENT_CACHE_SIZE=3 ++# CONFIG_VXFS_FS is not set ++# CONFIG_MINIX_FS is not set ++# CONFIG_OMFS_FS is not set ++# CONFIG_HPFS_FS is not set ++# CONFIG_QNX4FS_FS is not set ++CONFIG_ROMFS_FS=m ++CONFIG_ROMFS_BACKED_BY_BLOCK=y ++# CONFIG_ROMFS_BACKED_BY_MTD is not set ++# CONFIG_ROMFS_BACKED_BY_BOTH is not set ++CONFIG_ROMFS_ON_BLOCK=y ++# CONFIG_SYSV_FS is not set ++# CONFIG_UFS_FS is not set + CONFIG_NETWORK_FILESYSTEMS=y + CONFIG_NFS_FS=m + CONFIG_NFS_V3=y + CONFIG_NFS_V3_ACL=y + # CONFIG_NFS_V4 is not set +-# CONFIG_NFSD is not set ++# CONFIG_NFS_FSCACHE is not set ++CONFIG_NFSD=m ++CONFIG_NFSD_V3=y ++# CONFIG_NFSD_V3_ACL is not set ++CONFIG_NFSD_V4=y + CONFIG_LOCKD=m + CONFIG_LOCKD_V4=y ++CONFIG_EXPORTFS=m + CONFIG_NFS_ACL_SUPPORT=m + CONFIG_NFS_COMMON=y + CONFIG_SUNRPC=m +-# CONFIG_RPCSEC_GSS_KRB5 is not set ++CONFIG_SUNRPC_GSS=m ++CONFIG_RPCSEC_GSS_KRB5=m + # CONFIG_RPCSEC_GSS_SPKM3 is not set + # CONFIG_SMB_FS is not set +-# CONFIG_CIFS is not set ++CONFIG_CIFS=m ++# CONFIG_CIFS_STATS is not set ++# CONFIG_CIFS_WEAK_PW_HASH is not set ++# CONFIG_CIFS_UPCALL is not set ++# CONFIG_CIFS_XATTR is not set ++# CONFIG_CIFS_DEBUG2 is not set ++# CONFIG_CIFS_DFS_UPCALL is not set ++# CONFIG_CIFS_EXPERIMENTAL is not set + # CONFIG_NCP_FS is not set + # CONFIG_CODA_FS is not set + # CONFIG_AFS_FS is not set +@@ -1643,177 +2013,205 @@ + # CONFIG_PARTITION_ADVANCED is not set + CONFIG_MSDOS_PARTITION=y + CONFIG_NLS=y +-CONFIG_NLS_DEFAULT="utf-8" +-# CONFIG_NLS_CODEPAGE_437 is not set +-# CONFIG_NLS_CODEPAGE_737 is not set +-# CONFIG_NLS_CODEPAGE_775 is not set +-# CONFIG_NLS_CODEPAGE_850 is not set +-# CONFIG_NLS_CODEPAGE_852 is not set +-# CONFIG_NLS_CODEPAGE_855 is not set +-# CONFIG_NLS_CODEPAGE_857 is not set +-# CONFIG_NLS_CODEPAGE_860 is not set +-# CONFIG_NLS_CODEPAGE_861 is not set +-# CONFIG_NLS_CODEPAGE_862 is not set +-# CONFIG_NLS_CODEPAGE_863 is not set +-# CONFIG_NLS_CODEPAGE_864 is not set +-# CONFIG_NLS_CODEPAGE_865 is not set +-# CONFIG_NLS_CODEPAGE_866 is not set +-# CONFIG_NLS_CODEPAGE_869 is not set +-# CONFIG_NLS_CODEPAGE_936 is not set +-# CONFIG_NLS_CODEPAGE_950 is not set +-# CONFIG_NLS_CODEPAGE_932 is not set +-# CONFIG_NLS_CODEPAGE_949 is not set +-# CONFIG_NLS_CODEPAGE_874 is not set +-# CONFIG_NLS_ISO8859_8 is not set +-# CONFIG_NLS_CODEPAGE_1250 is not set +-# CONFIG_NLS_CODEPAGE_1251 is not set +-# CONFIG_NLS_ASCII is not set +-# CONFIG_NLS_ISO8859_1 is not set +-# CONFIG_NLS_ISO8859_2 is not set +-# CONFIG_NLS_ISO8859_3 is not set +-# CONFIG_NLS_ISO8859_4 is not set +-# CONFIG_NLS_ISO8859_5 is not set +-# CONFIG_NLS_ISO8859_6 is not set +-# CONFIG_NLS_ISO8859_7 is not set +-# CONFIG_NLS_ISO8859_9 is not set +-# CONFIG_NLS_ISO8859_13 is not set +-# CONFIG_NLS_ISO8859_14 is not set +-# CONFIG_NLS_ISO8859_15 is not set +-# CONFIG_NLS_KOI8_R is not set +-# CONFIG_NLS_KOI8_U is not set +-# CONFIG_NLS_UTF8 is not set ++CONFIG_NLS_DEFAULT="utf8" ++CONFIG_NLS_CODEPAGE_437=m ++CONFIG_NLS_CODEPAGE_737=m ++CONFIG_NLS_CODEPAGE_775=m ++CONFIG_NLS_CODEPAGE_850=m ++CONFIG_NLS_CODEPAGE_852=m ++CONFIG_NLS_CODEPAGE_855=m ++CONFIG_NLS_CODEPAGE_857=m ++CONFIG_NLS_CODEPAGE_860=m ++CONFIG_NLS_CODEPAGE_861=m ++CONFIG_NLS_CODEPAGE_862=m ++CONFIG_NLS_CODEPAGE_863=m ++CONFIG_NLS_CODEPAGE_864=m ++CONFIG_NLS_CODEPAGE_865=m ++CONFIG_NLS_CODEPAGE_866=m ++CONFIG_NLS_CODEPAGE_869=m ++CONFIG_NLS_CODEPAGE_936=m ++CONFIG_NLS_CODEPAGE_950=m ++CONFIG_NLS_CODEPAGE_932=m ++CONFIG_NLS_CODEPAGE_949=m ++CONFIG_NLS_CODEPAGE_874=m ++CONFIG_NLS_ISO8859_8=m ++CONFIG_NLS_CODEPAGE_1250=m ++CONFIG_NLS_CODEPAGE_1251=m ++CONFIG_NLS_ASCII=m ++CONFIG_NLS_ISO8859_1=m ++CONFIG_NLS_ISO8859_2=m ++CONFIG_NLS_ISO8859_3=m ++CONFIG_NLS_ISO8859_4=m ++CONFIG_NLS_ISO8859_5=m ++CONFIG_NLS_ISO8859_6=m ++CONFIG_NLS_ISO8859_7=m ++CONFIG_NLS_ISO8859_9=m ++CONFIG_NLS_ISO8859_13=m ++CONFIG_NLS_ISO8859_14=m ++CONFIG_NLS_ISO8859_15=m ++CONFIG_NLS_KOI8_R=m ++CONFIG_NLS_KOI8_U=m ++CONFIG_NLS_UTF8=y + # CONFIG_DLM is not set + + # + # Kernel hacking + # + CONFIG_TRACE_IRQFLAGS_SUPPORT=y +-CONFIG_PRINTK_TIME=y ++# CONFIG_PRINTK_TIME is not set + CONFIG_ENABLE_WARN_DEPRECATED=y + CONFIG_ENABLE_MUST_CHECK=y + CONFIG_FRAME_WARN=1024 + # CONFIG_MAGIC_SYSRQ is not set + CONFIG_STRIP_ASM_SYMS=y + # CONFIG_UNUSED_SYMBOLS is not set +-# CONFIG_DEBUG_FS is not set ++CONFIG_DEBUG_FS=y + # CONFIG_HEADERS_CHECK is not set + # CONFIG_DEBUG_KERNEL is not set +-# CONFIG_SLUB_DEBUG_ON is not set +-# CONFIG_SLUB_STATS is not set ++CONFIG_STACKTRACE=y + # CONFIG_DEBUG_MEMORY_INIT is not set + # CONFIG_RCU_CPU_STALL_DETECTOR is not set +-CONFIG_SYSCTL_SYSCALL_CHECK=y ++# CONFIG_SYSCTL_SYSCALL_CHECK is not set ++CONFIG_NOP_TRACER=y ++CONFIG_HAVE_FUNCTION_TRACER=y ++CONFIG_HAVE_FUNCTION_GRAPH_TRACER=y ++CONFIG_HAVE_FUNCTION_TRACE_MCOUNT_TEST=y ++CONFIG_HAVE_DYNAMIC_FTRACE=y ++CONFIG_HAVE_FTRACE_MCOUNT_RECORD=y ++CONFIG_RING_BUFFER=y ++CONFIG_EVENT_TRACING=y ++CONFIG_CONTEXT_SWITCH_TRACER=y ++CONFIG_RING_BUFFER_ALLOW_SWAP=y ++CONFIG_TRACING=y + CONFIG_TRACING_SUPPORT=y + # CONFIG_FTRACE is not set ++# CONFIG_DYNAMIC_DEBUG is not set + # CONFIG_SAMPLES is not set + CONFIG_HAVE_ARCH_KGDB=y ++CONFIG_EARLY_PRINTK=y + # CONFIG_CMDLINE_BOOL is not set + + # + # Security options + # +-# CONFIG_KEYS is not set ++CONFIG_KEYS=y ++CONFIG_KEYS_DEBUG_PROC_KEYS=y + # CONFIG_SECURITY is not set + # CONFIG_SECURITYFS is not set +-# CONFIG_SECURITY_FILE_CAPABILITIES is not set ++# CONFIG_DEFAULT_SECURITY_SELINUX is not set ++# CONFIG_DEFAULT_SECURITY_SMACK is not set ++# CONFIG_DEFAULT_SECURITY_TOMOYO is not set ++CONFIG_DEFAULT_SECURITY_DAC=y ++CONFIG_DEFAULT_SECURITY="" ++CONFIG_XOR_BLOCKS=m ++CONFIG_ASYNC_CORE=m ++CONFIG_ASYNC_MEMCPY=m ++CONFIG_ASYNC_XOR=m ++CONFIG_ASYNC_PQ=m ++CONFIG_ASYNC_RAID6_RECOV=m + CONFIG_CRYPTO=y + + # + # Crypto core or helper + # ++CONFIG_CRYPTO_FIPS=y + CONFIG_CRYPTO_ALGAPI=y + CONFIG_CRYPTO_ALGAPI2=y ++CONFIG_CRYPTO_AEAD=m + CONFIG_CRYPTO_AEAD2=y +-CONFIG_CRYPTO_BLKCIPHER=y ++CONFIG_CRYPTO_BLKCIPHER=m + CONFIG_CRYPTO_BLKCIPHER2=y ++CONFIG_CRYPTO_HASH=y + CONFIG_CRYPTO_HASH2=y ++CONFIG_CRYPTO_RNG=m + CONFIG_CRYPTO_RNG2=y + CONFIG_CRYPTO_PCOMP=y +-CONFIG_CRYPTO_MANAGER=y ++CONFIG_CRYPTO_MANAGER=m + CONFIG_CRYPTO_MANAGER2=y +-# CONFIG_CRYPTO_GF128MUL is not set +-# CONFIG_CRYPTO_NULL is not set ++CONFIG_CRYPTO_GF128MUL=m ++CONFIG_CRYPTO_NULL=m + CONFIG_CRYPTO_WORKQUEUE=y +-# CONFIG_CRYPTO_CRYPTD is not set +-# CONFIG_CRYPTO_AUTHENC is not set +-# CONFIG_CRYPTO_TEST is not set ++CONFIG_CRYPTO_CRYPTD=m ++CONFIG_CRYPTO_AUTHENC=m ++CONFIG_CRYPTO_TEST=m + + # + # Authenticated Encryption with Associated Data + # +-# CONFIG_CRYPTO_CCM is not set +-# CONFIG_CRYPTO_GCM is not set +-# CONFIG_CRYPTO_SEQIV is not set ++CONFIG_CRYPTO_CCM=m ++CONFIG_CRYPTO_GCM=m ++CONFIG_CRYPTO_SEQIV=m + + # + # Block modes + # +-CONFIG_CRYPTO_CBC=y +-# CONFIG_CRYPTO_CTR is not set ++CONFIG_CRYPTO_CBC=m ++CONFIG_CRYPTO_CTR=m + # CONFIG_CRYPTO_CTS is not set +-# CONFIG_CRYPTO_ECB is not set +-# CONFIG_CRYPTO_LRW is not set +-# CONFIG_CRYPTO_PCBC is not set +-# CONFIG_CRYPTO_XTS is not set ++CONFIG_CRYPTO_ECB=m ++CONFIG_CRYPTO_LRW=m ++CONFIG_CRYPTO_PCBC=m ++CONFIG_CRYPTO_XTS=m + + # + # Hash modes + # +-# CONFIG_CRYPTO_HMAC is not set +-# CONFIG_CRYPTO_XCBC is not set ++CONFIG_CRYPTO_HMAC=m ++CONFIG_CRYPTO_XCBC=m + # CONFIG_CRYPTO_VMAC is not set + + # + # Digest + # +-# CONFIG_CRYPTO_CRC32C is not set +-# CONFIG_CRYPTO_GHASH is not set +-# CONFIG_CRYPTO_MD4 is not set +-# CONFIG_CRYPTO_MD5 is not set +-# CONFIG_CRYPTO_MICHAEL_MIC is not set +-# CONFIG_CRYPTO_RMD128 is not set +-# CONFIG_CRYPTO_RMD160 is not set +-# CONFIG_CRYPTO_RMD256 is not set +-# CONFIG_CRYPTO_RMD320 is not set +-# CONFIG_CRYPTO_SHA1 is not set +-# CONFIG_CRYPTO_SHA256 is not set +-# CONFIG_CRYPTO_SHA512 is not set +-# CONFIG_CRYPTO_TGR192 is not set +-# CONFIG_CRYPTO_WP512 is not set ++CONFIG_CRYPTO_CRC32C=m ++CONFIG_CRYPTO_GHASH=m ++CONFIG_CRYPTO_MD4=m ++CONFIG_CRYPTO_MD5=y ++CONFIG_CRYPTO_MICHAEL_MIC=m ++CONFIG_CRYPTO_RMD128=m ++CONFIG_CRYPTO_RMD160=m ++CONFIG_CRYPTO_RMD256=m ++CONFIG_CRYPTO_RMD320=m ++CONFIG_CRYPTO_SHA1=m ++CONFIG_CRYPTO_SHA256=m ++CONFIG_CRYPTO_SHA512=m ++CONFIG_CRYPTO_TGR192=m ++CONFIG_CRYPTO_WP512=m + + # + # Ciphers + # +-# CONFIG_CRYPTO_AES is not set +-# CONFIG_CRYPTO_ANUBIS is not set +-# CONFIG_CRYPTO_ARC4 is not set +-# CONFIG_CRYPTO_BLOWFISH is not set +-# CONFIG_CRYPTO_CAMELLIA is not set +-# CONFIG_CRYPTO_CAST5 is not set +-# CONFIG_CRYPTO_CAST6 is not set +-# CONFIG_CRYPTO_DES is not set +-# CONFIG_CRYPTO_FCRYPT is not set +-# CONFIG_CRYPTO_KHAZAD is not set +-# CONFIG_CRYPTO_SALSA20 is not set +-# CONFIG_CRYPTO_SEED is not set +-# CONFIG_CRYPTO_SERPENT is not set +-# CONFIG_CRYPTO_TEA is not set +-# CONFIG_CRYPTO_TWOFISH is not set ++CONFIG_CRYPTO_AES=m ++CONFIG_CRYPTO_ANUBIS=m ++CONFIG_CRYPTO_ARC4=m ++CONFIG_CRYPTO_BLOWFISH=m ++CONFIG_CRYPTO_CAMELLIA=m ++CONFIG_CRYPTO_CAST5=m ++CONFIG_CRYPTO_CAST6=m ++CONFIG_CRYPTO_DES=m ++CONFIG_CRYPTO_FCRYPT=m ++CONFIG_CRYPTO_KHAZAD=m ++CONFIG_CRYPTO_SALSA20=m ++CONFIG_CRYPTO_SEED=m ++CONFIG_CRYPTO_SERPENT=m ++CONFIG_CRYPTO_TEA=m ++CONFIG_CRYPTO_TWOFISH=m ++CONFIG_CRYPTO_TWOFISH_COMMON=m + + # + # Compression + # +-# CONFIG_CRYPTO_DEFLATE is not set +-# CONFIG_CRYPTO_ZLIB is not set +-# CONFIG_CRYPTO_LZO is not set ++CONFIG_CRYPTO_DEFLATE=m ++CONFIG_CRYPTO_ZLIB=m ++CONFIG_CRYPTO_LZO=m + + # + # Random Number Generation + # +-# CONFIG_CRYPTO_ANSI_CPRNG is not set ++CONFIG_CRYPTO_ANSI_CPRNG=m + CONFIG_CRYPTO_HW=y + # CONFIG_CRYPTO_DEV_HIFN_795X is not set +-# CONFIG_BINARY_PRINTF is not set ++CONFIG_BINARY_PRINTF=y + + # + # Library routines +@@ -1821,14 +2219,20 @@ + CONFIG_BITREVERSE=y + CONFIG_GENERIC_FIND_LAST_BIT=y + # CONFIG_CRC_CCITT is not set +-# CONFIG_CRC16 is not set ++CONFIG_CRC16=y + CONFIG_CRC_T10DIF=y + # CONFIG_CRC_ITU_T is not set + CONFIG_CRC32=y + # CONFIG_CRC7 is not set +-# CONFIG_LIBCRC32C is not set ++CONFIG_LIBCRC32C=m + CONFIG_AUDIT_GENERIC=y +-CONFIG_ZLIB_INFLATE=m ++CONFIG_ZLIB_INFLATE=y ++CONFIG_ZLIB_DEFLATE=m ++CONFIG_LZO_COMPRESS=m ++CONFIG_LZO_DECOMPRESS=m ++CONFIG_DECOMPRESS_GZIP=y ++CONFIG_DECOMPRESS_BZIP2=y ++CONFIG_DECOMPRESS_LZMA=y + CONFIG_HAS_IOMEM=y + CONFIG_HAS_IOPORT=y + CONFIG_HAS_DMA=y +diff -Nur linux-2.6.33/arch/mips/include/asm/ftrace.h linux-lemote/arch/mips/include/asm/ftrace.h +--- linux-2.6.33/arch/mips/include/asm/ftrace.h 2010-02-24 19:52:17.000000000 +0100 ++++ linux-lemote/arch/mips/include/asm/ftrace.h 2010-03-06 16:43:00.000000000 +0100 +@@ -4,7 +4,7 @@ + * more details. + * + * Copyright (C) 2009 DSLab, Lanzhou University, China +- * Author: Wu Zhangjin <wuzj@lemote.com> ++ * Author: Wu Zhangjin <wuzhangjin@gmail.com> + */ + + #ifndef _ASM_MIPS_FTRACE_H +diff -Nur linux-2.6.33/arch/mips/include/asm/mach-loongson/cpu-feature-overrides.h linux-lemote/arch/mips/include/asm/mach-loongson/cpu-feature-overrides.h +--- linux-2.6.33/arch/mips/include/asm/mach-loongson/cpu-feature-overrides.h 2010-02-24 19:52:17.000000000 +0100 ++++ linux-lemote/arch/mips/include/asm/mach-loongson/cpu-feature-overrides.h 2010-03-06 16:43:00.000000000 +0100 +@@ -3,7 +3,7 @@ + * License. See the file "COPYING" in the main directory of this archive + * for more details. + * +- * Copyright (C) 2009 Wu Zhangjin <wuzj@lemote.com> ++ * Copyright (C) 2009 Wu Zhangjin <wuzhangjin@gmail.com> + * Copyright (C) 2009 Philippe Vachon <philippe@cowpig.ca> + * Copyright (C) 2009 Zhang Le <r0bertz@gentoo.org> + * +diff -Nur linux-2.6.33/arch/mips/include/asm/mach-loongson/cs5536/cs5536.h linux-lemote/arch/mips/include/asm/mach-loongson/cs5536/cs5536.h +--- linux-2.6.33/arch/mips/include/asm/mach-loongson/cs5536/cs5536.h 2010-02-24 19:52:17.000000000 +0100 ++++ linux-lemote/arch/mips/include/asm/mach-loongson/cs5536/cs5536.h 2010-03-06 16:43:00.000000000 +0100 +@@ -301,5 +301,40 @@ + /* GPIO : I/O SPACE; REG : 32BITS */ + #define GPIOL_OUT_VAL 0x00 + #define GPIOL_OUT_EN 0x04 ++#define GPIOL_OUT_AUX1_SEL 0x10 ++/* SMB : I/O SPACE, REG : 8BITS WIDTH */ ++#define SMB_SDA 0x00 ++#define SMB_STS 0x01 ++#define SMB_STS_SLVSTP (1 << 7) ++#define SMB_STS_SDAST (1 << 6) ++#define SMB_STS_BER (1 << 5) ++#define SMB_STS_NEGACK (1 << 4) ++#define SMB_STS_STASTR (1 << 3) ++#define SMB_STS_NMATCH (1 << 2) ++#define SMB_STS_MASTER (1 << 1) ++#define SMB_STS_XMIT (1 << 0) ++#define SMB_CTRL_STS 0x02 ++#define SMB_CSTS_TGSTL (1 << 5) ++#define SMB_CSTS_TSDA (1 << 4) ++#define SMB_CSTS_GCMTCH (1 << 3) ++#define SMB_CSTS_MATCH (1 << 2) ++#define SMB_CSTS_BB (1 << 1) ++#define SMB_CSTS_BUSY (1 << 0) ++#define SMB_CTRL1 0x03 ++#define SMB_CTRL1_STASTRE (1 << 7) ++#define SMB_CTRL1_NMINTE (1 << 6) ++#define SMB_CTRL1_GCMEN (1 << 5) ++#define SMB_CTRL1_ACK (1 << 4) ++#define SMB_CTRL1_RSVD (1 << 3) ++#define SMB_CTRL1_INTEN (1 << 2) ++#define SMB_CTRL1_STOP (1 << 1) ++#define SMB_CTRL1_START (1 << 0) ++#define SMB_ADDR 0x04 ++#define SMB_ADDR_SAEN (1 << 7) ++#define SMB_CONTROLLER_ADDR (0xef << 0) ++#define SMB_CTRL2 0x05 ++#define SMB_FREQ (0x20 << 1) ++#define SMB_ENABLE (0x01 << 0) ++#define SMB_CTRL3 0x06 + + #endif /* _CS5536_H */ +diff -Nur linux-2.6.33/arch/mips/include/asm/mach-loongson/cs5536/cs5536_mfgpt.h linux-lemote/arch/mips/include/asm/mach-loongson/cs5536/cs5536_mfgpt.h +--- linux-2.6.33/arch/mips/include/asm/mach-loongson/cs5536/cs5536_mfgpt.h 2010-02-24 19:52:17.000000000 +0100 ++++ linux-lemote/arch/mips/include/asm/mach-loongson/cs5536/cs5536_mfgpt.h 2010-03-06 16:43:00.000000000 +0100 +@@ -32,4 +32,9 @@ + #define MFGPT0_CNT (MFGPT_BASE + 4) + #define MFGPT0_SETUP (MFGPT_BASE + 6) + ++#define MFGPT2_CMP1 (MFGPT_BASE + 0x10) ++#define MFGPT2_CMP2 (MFGPT_BASE + 0x12) ++#define MFGPT2_CNT (MFGPT_BASE + 0x14) ++#define MFGPT2_SETUP (MFGPT_BASE + 0x16) ++ + #endif /*!_CS5536_MFGPT_H */ +diff -Nur linux-2.6.33/arch/mips/include/asm/mach-loongson/cs5536/cs5536_vsm.h linux-lemote/arch/mips/include/asm/mach-loongson/cs5536/cs5536_vsm.h +--- linux-2.6.33/arch/mips/include/asm/mach-loongson/cs5536/cs5536_vsm.h 2010-02-24 19:52:17.000000000 +0100 ++++ linux-lemote/arch/mips/include/asm/mach-loongson/cs5536/cs5536_vsm.h 2010-03-06 16:43:00.000000000 +0100 +@@ -2,7 +2,7 @@ + * the read/write interfaces for Virtual Support Module(VSM) + * + * Copyright (C) 2009 Lemote, Inc. +- * Author: Wu Zhangjin <wuzj@lemote.com> ++ * Author: Wu Zhangjin <wuzhangjin@gmail.com> + */ + + #ifndef _CS5536_VSM_H +diff -Nur linux-2.6.33/arch/mips/include/asm/mach-loongson/ec_kb3310b.h linux-lemote/arch/mips/include/asm/mach-loongson/ec_kb3310b.h +--- linux-2.6.33/arch/mips/include/asm/mach-loongson/ec_kb3310b.h 1970-01-01 01:00:00.000000000 +0100 ++++ linux-lemote/arch/mips/include/asm/mach-loongson/ec_kb3310b.h 2010-03-06 16:43:00.000000000 +0100 +@@ -0,0 +1,191 @@ ++/* ++ * KB3310B Embedded Controller ++ * ++ * Copyright (C) 2008 Lemote Inc. ++ * Author: liujl <liujl@lemote.com>, 2008-03-14 ++ * Copyright (C) 2009 Lemote Inc. ++ * Author: Wu Zhangjin <wuzhangjin@gmail.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. ++ */ ++ ++#ifndef _EC_KB3310B_H ++#define _EC_KB3310B_H ++ ++extern unsigned char ec_read(unsigned short addr); ++extern void ec_write(unsigned short addr, unsigned char val); ++extern int ec_query_seq(unsigned char cmd); ++extern int ec_query_event_num(void); ++extern int ec_get_event_num(void); ++ ++typedef int (*sci_handler) (int status); ++extern sci_handler yeeloong_report_lid_status; ++ ++#define SCI_IRQ_NUM 0x0A ++ ++/* ++ * The following registers are determined by the EC index configuration. ++ * 1, fill the PORT_HIGH as EC register high part. ++ * 2, fill the PORT_LOW as EC register low part. ++ * 3, fill the PORT_DATA as EC register write data or get the data from it. ++ */ ++#define EC_IO_PORT_HIGH 0x0381 ++#define EC_IO_PORT_LOW 0x0382 ++#define EC_IO_PORT_DATA 0x0383 ++ ++/* ++ * EC delay time is 500us for register and status access ++ */ ++#define EC_REG_DELAY 500 /* unit : us */ ++#define EC_CMD_TIMEOUT 0x1000 ++ ++/* ++ * EC access port for SCI communication ++ */ ++#define EC_CMD_PORT 0x66 ++#define EC_STS_PORT 0x66 ++#define EC_DAT_PORT 0x62 ++#define CMD_INIT_IDLE_MODE 0xdd ++#define CMD_EXIT_IDLE_MODE 0xdf ++#define CMD_INIT_RESET_MODE 0xd8 ++#define CMD_REBOOT_SYSTEM 0x8c ++#define CMD_GET_EVENT_NUM 0x84 ++#define CMD_PROGRAM_PIECE 0xda ++ ++/* Temperature & Fan registers */ ++#define REG_TEMPERATURE_VALUE 0xF458 ++#define REG_FAN_AUTO_MAN_SWITCH 0xF459 ++#define BIT_FAN_AUTO 0 ++#define BIT_FAN_MANUAL 1 ++#define REG_FAN_CONTROL 0xF4D2 ++#define BIT_FAN_CONTROL_ON (1 << 0) ++#define BIT_FAN_CONTROL_OFF (0 << 0) ++#define REG_FAN_STATUS 0xF4DA ++#define BIT_FAN_STATUS_ON (1 << 0) ++#define BIT_FAN_STATUS_OFF (0 << 0) ++#define REG_FAN_SPEED_HIGH 0xFE22 ++#define REG_FAN_SPEED_LOW 0xFE23 ++#define REG_FAN_SPEED_LEVEL 0xF4CC ++/* Fan speed divider */ ++#define FAN_SPEED_DIVIDER 480000 /* (60*1000*1000/62.5/2)*/ ++ ++/* Battery registers */ ++#define REG_BAT_DESIGN_CAP_HIGH 0xF77D ++#define REG_BAT_DESIGN_CAP_LOW 0xF77E ++#define REG_BAT_FULLCHG_CAP_HIGH 0xF780 ++#define REG_BAT_FULLCHG_CAP_LOW 0xF781 ++#define REG_BAT_DESIGN_VOL_HIGH 0xF782 ++#define REG_BAT_DESIGN_VOL_LOW 0xF783 ++#define REG_BAT_CURRENT_HIGH 0xF784 ++#define REG_BAT_CURRENT_LOW 0xF785 ++#define REG_BAT_VOLTAGE_HIGH 0xF786 ++#define REG_BAT_VOLTAGE_LOW 0xF787 ++#define REG_BAT_TEMPERATURE_HIGH 0xF788 ++#define REG_BAT_TEMPERATURE_LOW 0xF789 ++#define REG_BAT_RELATIVE_CAP_HIGH 0xF492 ++#define REG_BAT_RELATIVE_CAP_LOW 0xF493 ++#define REG_BAT_VENDOR 0xF4C4 ++#define FLAG_BAT_VENDOR_SANYO 0x01 ++#define FLAG_BAT_VENDOR_SIMPLO 0x02 ++#define REG_BAT_CELL_COUNT 0xF4C6 ++#define FLAG_BAT_CELL_3S1P 0x03 ++#define FLAG_BAT_CELL_3S2P 0x06 ++#define REG_BAT_CHARGE 0xF4A2 ++#define FLAG_BAT_CHARGE_DISCHARGE 0x01 ++#define FLAG_BAT_CHARGE_CHARGE 0x02 ++#define FLAG_BAT_CHARGE_ACPOWER 0x00 ++#define REG_BAT_STATUS 0xF4B0 ++#define BIT_BAT_STATUS_LOW (1 << 5) ++#define BIT_BAT_STATUS_DESTROY (1 << 2) ++#define BIT_BAT_STATUS_FULL (1 << 1) ++#define BIT_BAT_STATUS_IN (1 << 0) ++#define REG_BAT_CHARGE_STATUS 0xF4B1 ++#define BIT_BAT_CHARGE_STATUS_OVERTEMP (1 << 2) ++#define BIT_BAT_CHARGE_STATUS_PRECHG (1 << 1) ++#define REG_BAT_STATE 0xF482 ++#define BIT_BAT_STATE_CHARGING (1 << 1) ++#define BIT_BAT_STATE_DISCHARGING (1 << 0) ++#define REG_BAT_POWER 0xF440 ++#define BIT_BAT_POWER_S3 (1 << 2) ++#define BIT_BAT_POWER_ON (1 << 1) ++#define BIT_BAT_POWER_ACIN (1 << 0) ++ ++/* Audio: rd/wr */ ++#define REG_AUDIO_VOLUME 0xF46C ++#define REG_AUDIO_MUTE 0xF4E7 ++#define REG_AUDIO_BEEP 0xF4D0 ++/* USB port power or not: rd/wr */ ++#define REG_USB0_FLAG 0xF461 ++#define REG_USB1_FLAG 0xF462 ++#define REG_USB2_FLAG 0xF463 ++#define BIT_USB_FLAG_ON 1 ++#define BIT_USB_FLAG_OFF 0 ++/* LID */ ++#define REG_LID_DETECT 0xF4BD ++#define BIT_LID_DETECT_ON 1 ++#define BIT_LID_DETECT_OFF 0 ++/* CRT */ ++#define REG_CRT_DETECT 0xF4AD ++#define BIT_CRT_DETECT_PLUG 1 ++#define BIT_CRT_DETECT_UNPLUG 0 ++/* LCD backlight brightness adjust: 9 levels */ ++#define REG_DISPLAY_BRIGHTNESS 0xF4F5 ++/* Black screen Status */ ++#define BIT_DISPLAY_LCD_ON 1 ++#define BIT_DISPLAY_LCD_OFF 0 ++/* LCD backlight control: off/restore */ ++#define REG_BACKLIGHT_CTRL 0xF7BD ++#define BIT_BACKLIGHT_ON 1 ++#define BIT_BACKLIGHT_OFF 0 ++/* Reset the machine auto-clear: rd/wr */ ++#define REG_RESET 0xF4EC ++#define BIT_RESET_ON 1 ++/* Light the led: rd/wr */ ++#define REG_LED 0xF4C8 ++#define BIT_LED_RED_POWER (1 << 0) ++#define BIT_LED_ORANGE_POWER (1 << 1) ++#define BIT_LED_GREEN_CHARGE (1 << 2) ++#define BIT_LED_RED_CHARGE (1 << 3) ++#define BIT_LED_NUMLOCK (1 << 4) ++/* Test led mode, all led on/off */ ++#define REG_LED_TEST 0xF4C2 ++#define BIT_LED_TEST_IN 1 ++#define BIT_LED_TEST_OUT 0 ++/* Camera on/off */ ++#define REG_CAMERA_STATUS 0xF46A ++#define BIT_CAMERA_STATUS_ON 1 ++#define BIT_CAMERA_STATUS_OFF 0 ++#define REG_CAMERA_CONTROL 0xF7B7 ++#define BIT_CAMERA_CONTROL_OFF 0 ++#define BIT_CAMERA_CONTROL_ON 1 ++/* Wlan Status */ ++#define REG_WLAN 0xF4FA ++#define BIT_WLAN_ON 1 ++#define BIT_WLAN_OFF 0 ++#define REG_DISPLAY_LCD 0xF79F ++ ++/* SCI Event Number from EC */ ++enum { ++ EVENT_LID = 0x23, /* Turn on/off LID */ ++ EVENT_DISPLAY_TOGGLE, /* Fn+F3 for display switch */ ++ EVENT_SLEEP, /* Fn+F1 for entering sleep mode */ ++ EVENT_OVERTEMP, /* Over-temperature happened */ ++ EVENT_CRT_DETECT, /* CRT is connected */ ++ EVENT_CAMERA, /* Camera on/off */ ++ EVENT_USB_OC2, /* USB2 Over Current occurred */ ++ EVENT_USB_OC0, /* USB0 Over Current occurred */ ++ EVENT_BLACK_SCREEN, /* Turn on/off backlight */ ++ EVENT_AUDIO_MUTE, /* Mute on/off */ ++ EVENT_DISPLAY_BRIGHTNESS,/* LCD backlight brightness adjust */ ++ EVENT_AC_BAT, /* AC & Battery relative issue */ ++ EVENT_AUDIO_VOLUME, /* Volume adjust */ ++ EVENT_WLAN, /* Wlan on/off */ ++}; ++ ++#define EVENT_START EVENT_LID ++#define EVENT_END EVENT_WLAN ++ ++#endif /* !_EC_KB3310B_H */ +diff -Nur linux-2.6.33/arch/mips/include/asm/mach-loongson/loongson.h linux-lemote/arch/mips/include/asm/mach-loongson/loongson.h +--- linux-2.6.33/arch/mips/include/asm/mach-loongson/loongson.h 2010-02-24 19:52:17.000000000 +0100 ++++ linux-lemote/arch/mips/include/asm/mach-loongson/loongson.h 2010-03-06 16:43:00.000000000 +0100 +@@ -1,12 +1,11 @@ + /* + * Copyright (C) 2009 Lemote, Inc. +- * Author: Wu Zhangjin <wuzj@lemote.com> ++ * Author: Wu Zhangjin <wuzhangjin@gmail.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. +- * + */ + + #ifndef __ASM_MACH_LOONGSON_LOONGSON_H +@@ -23,7 +22,7 @@ + extern void mach_prepare_shutdown(void); + + /* environment arguments from bootloader */ +-extern unsigned long bus_clock, cpu_clock_freq; ++extern unsigned long cpu_clock_freq; + extern unsigned long memsize, highmemsize; + + /* loongson-specific command line, env and memory initialization */ +@@ -43,6 +42,12 @@ + #endif + } + ++/* ++ * Copy kernel command line from arcs_cmdline ++ */ ++#include <asm/setup.h> ++extern char loongson_cmdline[COMMAND_LINE_SIZE]; ++ + /* irq operation functions */ + extern void bonito_irqdispatch(void); + extern void __init bonito_irq_init(void); +diff -Nur linux-2.6.33/arch/mips/include/asm/mach-loongson/machine.h linux-lemote/arch/mips/include/asm/mach-loongson/machine.h +--- linux-2.6.33/arch/mips/include/asm/mach-loongson/machine.h 2010-02-24 19:52:17.000000000 +0100 ++++ linux-lemote/arch/mips/include/asm/mach-loongson/machine.h 2010-03-06 16:43:00.000000000 +0100 +@@ -1,6 +1,6 @@ + /* +- * Copyright (C) 2009 Lemote, Inc. & Institute of Computing Technology +- * Author: Wu Zhangjin <wuzj@lemote.com> ++ * Copyright (C) 2009 Lemote, Inc. ++ * Author: Wu Zhangjin <wuzhangjin@gmail.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 +diff -Nur linux-2.6.33/arch/mips/include/asm/mach-loongson/mem.h linux-lemote/arch/mips/include/asm/mach-loongson/mem.h +--- linux-2.6.33/arch/mips/include/asm/mach-loongson/mem.h 2010-02-24 19:52:17.000000000 +0100 ++++ linux-lemote/arch/mips/include/asm/mach-loongson/mem.h 2010-03-06 16:43:00.000000000 +0100 +@@ -1,6 +1,6 @@ + /* + * Copyright (C) 2009 Lemote, Inc. +- * Author: Wu Zhangjin <wuzj@lemote.com> ++ * Author: Wu Zhangjin <wuzhangjin@gmail.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 +diff -Nur linux-2.6.33/arch/mips/include/asm/mach-loongson/pci.h linux-lemote/arch/mips/include/asm/mach-loongson/pci.h +--- linux-2.6.33/arch/mips/include/asm/mach-loongson/pci.h 2010-02-24 19:52:17.000000000 +0100 ++++ linux-lemote/arch/mips/include/asm/mach-loongson/pci.h 2010-03-06 16:43:00.000000000 +0100 +@@ -1,23 +1,12 @@ + /* + * Copyright (c) 2008 Zhang Le <r0bertz@gentoo.org> +- * Copyright (c) 2009 Wu Zhangjin <wuzj@lemote.com> ++ * Copyright (c) 2009 Wu Zhangjin <wuzhangjin@gmail.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., 675 Mass Ave, Cambridge, MA +- * 02139, USA. + */ + + #ifndef __ASM_MACH_LOONGSON_PCI_H_ +diff -Nur linux-2.6.33/arch/mips/include/asm/stackframe.h linux-lemote/arch/mips/include/asm/stackframe.h +--- linux-2.6.33/arch/mips/include/asm/stackframe.h 2010-02-24 19:52:17.000000000 +0100 ++++ linux-lemote/arch/mips/include/asm/stackframe.h 2010-03-06 16:43:00.000000000 +0100 +@@ -121,6 +121,25 @@ + .endm + #else + .macro get_saved_sp /* Uniprocessor variation */ ++ /* ++ * clear BTB(branch target buffer), forbid RAS(row address ++ * strobe) to make cpu execute predictively via ++ * loongson2-specific 64bit diagnostic register ++ */ ++#ifdef CONFIG_CPU_LOONGSON2F ++ move k0, ra ++ jal 1f ++ nop ++1: jal 1f ++ nop ++1: jal 1f ++ nop ++1: jal 1f ++ nop ++1: move ra, k0 ++ li k0, 3 ++ mtc0 k0, $22 ++#endif + #if defined(CONFIG_32BIT) || defined(KBUILD_64BIT_SYM32) + lui k1, %hi(kernelsp) + #else +diff -Nur linux-2.6.33/arch/mips/Kconfig linux-lemote/arch/mips/Kconfig +--- linux-2.6.33/arch/mips/Kconfig 2010-02-24 19:52:17.000000000 +0100 ++++ linux-lemote/arch/mips/Kconfig 2010-03-06 16:42:59.000000000 +0100 +@@ -180,7 +180,7 @@ + + config MACH_LOONGSON + bool "Loongson family of machines" +- select SYS_SUPPORTS_ZBOOT_UART16550 ++ select SYS_SUPPORTS_ZBOOT + help + This enables the support of Loongson family of machines. + +@@ -1934,6 +1934,18 @@ + source "kernel/time/Kconfig" + + # ++# High Resolution sched_clock() Configuration ++# ++ ++config CPU_HAS_FIXED_C0_COUNT ++ bool ++ ++config CPU_SUPPORTS_HR_SCHED_CLOCK ++ bool ++ depends on CPU_HAS_FIXED_C0_COUNT || !CPU_FREQ ++ default y ++ ++# + # Timer Interrupt Frequency Configuration + # + +diff -Nur linux-2.6.33/arch/mips/Kconfig.debug linux-lemote/arch/mips/Kconfig.debug +--- linux-2.6.33/arch/mips/Kconfig.debug 2010-02-24 19:52:17.000000000 +0100 ++++ linux-lemote/arch/mips/Kconfig.debug 2010-03-06 16:42:59.000000000 +0100 +@@ -102,4 +102,22 @@ + arch/mips/include/asm/debug.h for debugging macros. + If unsure, say N. + ++config DEBUG_ZBOOT ++ bool "Enable compressed kernel support debugging" ++ depends on DEBUG_KERNEL && SYS_SUPPORTS_ZBOOT ++ help ++ If you want to add compressed kernel support to a new board, and the ++ board supports uart16550 compatible serial port, please select ++ SYS_SUPPORTS_ZBOOT_UART16550 for your board and enable this option to ++ debug it. ++ ++ If your board doesn't support uart16550 compatible serial port, you ++ can try to select SYS_SUPPORTS_ZBOOT and use the other methods to ++ debug it. for example, add a new serial port support just as ++ arch/mips/boot/compressed/uart-16550.c does. ++ ++ After the compressed kernel support works, please disable this option ++ to reduce the kernel image size and speed up the booting procedure a ++ little. ++ + endmenu +diff -Nur linux-2.6.33/arch/mips/kernel/cpufreq/loongson2_clock.c linux-lemote/arch/mips/kernel/cpufreq/loongson2_clock.c +--- linux-2.6.33/arch/mips/kernel/cpufreq/loongson2_clock.c 2010-02-24 19:52:17.000000000 +0100 ++++ linux-lemote/arch/mips/kernel/cpufreq/loongson2_clock.c 2010-03-06 16:43:01.000000000 +0100 +@@ -164,3 +164,7 @@ + spin_unlock_irqrestore(&loongson2_wait_lock, flags); + } + EXPORT_SYMBOL_GPL(loongson2_cpu_wait); ++ ++MODULE_AUTHOR("Yanhua <yanh@lemote.com>"); ++MODULE_DESCRIPTION("cpuclock driver of Loongson2F"); ++MODULE_LICENSE("GPL"); +diff -Nur linux-2.6.33/arch/mips/kernel/csrc-r4k.c linux-lemote/arch/mips/kernel/csrc-r4k.c +--- linux-2.6.33/arch/mips/kernel/csrc-r4k.c 2010-02-24 19:52:17.000000000 +0100 ++++ linux-lemote/arch/mips/kernel/csrc-r4k.c 2010-03-06 16:43:01.000000000 +0100 +@@ -6,10 +6,66 @@ + * Copyright (C) 2007 by Ralf Baechle + */ + #include <linux/clocksource.h> ++#include <linux/cnt32_to_63.h> + #include <linux/init.h> ++#include <linux/timer.h> + + #include <asm/time.h> + ++#ifdef CONFIG_CPU_SUPPORTS_HR_SCHED_CLOCK ++/* ++ * MIPS sched_clock implementation. ++ * ++ * Because the hardware timer period is quite short and because cnt32_to_63() ++ * needs to be called at least once per half period to work properly, a kernel ++ * timer is set up to ensure this requirement is always met. ++ * ++ * Please refer to include/linux/cnt32_to_63.h and arch/arm/plat-orion/time.c ++ */ ++#define CLOCK2NS_SCALE_FACTOR 8 ++ ++static unsigned long clock2ns_scale __read_mostly; ++ ++unsigned long long notrace sched_clock(void) ++{ ++ unsigned long long v = cnt32_to_63(read_c0_count()); ++ return (v * clock2ns_scale) >> CLOCK2NS_SCALE_FACTOR; ++} ++ ++static struct timer_list cnt32_to_63_keepwarm_timer; ++ ++static void cnt32_to_63_keepwarm(unsigned long data) ++{ ++ mod_timer(&cnt32_to_63_keepwarm_timer, round_jiffies(jiffies + data)); ++ sched_clock(); ++} ++#endif ++ ++static inline void setup_hres_sched_clock(unsigned long clock) ++{ ++#ifdef CONFIG_CPU_SUPPORTS_HR_SCHED_CLOCK ++ unsigned long long v; ++ unsigned long data; ++ ++ v = NSEC_PER_SEC; ++ v <<= CLOCK2NS_SCALE_FACTOR; ++ v += clock/2; ++ do_div(v, clock); ++ /* ++ * We want an even value to automatically clear the top bit ++ * returned by cnt32_to_63() without an additional run time ++ * instruction. So if the LSB is 1 then round it up. ++ */ ++ if (v & 1) ++ v++; ++ clock2ns_scale = v; ++ ++ data = 0x80000000UL / clock * HZ; ++ setup_timer(&cnt32_to_63_keepwarm_timer, cnt32_to_63_keepwarm, data); ++ mod_timer(&cnt32_to_63_keepwarm_timer, round_jiffies(jiffies + data)); ++#endif ++} ++ + static cycle_t c0_hpt_read(struct clocksource *cs) + { + return read_c0_count(); +@@ -27,6 +83,8 @@ + if (!cpu_has_counter || !mips_hpt_frequency) + return -ENXIO; + ++ setup_hres_sched_clock(mips_hpt_frequency); ++ + /* Calculate a somewhat reasonable rating value */ + clocksource_mips.rating = 200 + mips_hpt_frequency / 10000000; + +diff -Nur linux-2.6.33/arch/mips/kernel/ftrace.c linux-lemote/arch/mips/kernel/ftrace.c +--- linux-2.6.33/arch/mips/kernel/ftrace.c 2010-02-24 19:52:17.000000000 +0100 ++++ linux-lemote/arch/mips/kernel/ftrace.c 2010-03-06 16:43:01.000000000 +0100 +@@ -3,7 +3,7 @@ + * + * Copyright (C) 2007-2008 Steven Rostedt <srostedt@redhat.com> + * Copyright (C) 2009 DSLab, Lanzhou University, China +- * Author: Wu Zhangjin <wuzj@lemote.com> ++ * Author: Wu Zhangjin <wuzhangjin@gmail.com> + * + * Thanks goes to Steven Rostedt for writing the original x86 version. + */ +diff -Nur linux-2.6.33/arch/mips/kernel/mcount.S linux-lemote/arch/mips/kernel/mcount.S +--- linux-2.6.33/arch/mips/kernel/mcount.S 2010-02-24 19:52:17.000000000 +0100 ++++ linux-lemote/arch/mips/kernel/mcount.S 2010-03-06 16:43:01.000000000 +0100 +@@ -6,7 +6,7 @@ + * more details. + * + * Copyright (C) 2009 Lemote Inc. & DSLab, Lanzhou University, China +- * Author: Wu Zhangjin <wuzj@lemote.com> ++ * Author: Wu Zhangjin <wuzhangjin@gmail.com> + */ + + #include <asm/regdef.h> +diff -Nur linux-2.6.33/arch/mips/kernel/time.c linux-lemote/arch/mips/kernel/time.c +--- linux-2.6.33/arch/mips/kernel/time.c 2010-02-24 19:52:17.000000000 +0100 ++++ linux-lemote/arch/mips/kernel/time.c 2010-03-06 16:43:01.000000000 +0100 +@@ -119,6 +119,11 @@ + + void __init time_init(void) + { ++#ifdef CONFIG_HR_SCHED_CLOCK ++ if (!mips_clockevent_init() || !cpu_has_mfc0_count_bug()) ++ write_c0_count(0); ++#endif ++ + plat_time_init(); + + if (!mips_clockevent_init() || !cpu_has_mfc0_count_bug()) +diff -Nur linux-2.6.33/arch/mips/loongson/common/cmdline.c linux-lemote/arch/mips/loongson/common/cmdline.c +--- linux-2.6.33/arch/mips/loongson/common/cmdline.c 2010-02-24 19:52:17.000000000 +0100 ++++ linux-lemote/arch/mips/loongson/common/cmdline.c 2010-03-06 16:43:01.000000000 +0100 +@@ -10,23 +10,27 @@ + * Author: Fuxin Zhang, zhangfx@lemote.com + * + * Copyright (C) 2009 Lemote Inc. +- * Author: Wu Zhangjin, wuzj@lemote.com ++ * Author: Wu Zhangjin, wuzhangjin@gmail.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. + */ ++#include <linux/module.h> + #include <asm/bootinfo.h> + + #include <loongson.h> + +-int prom_argc; +-/* pmon passes arguments in 32bit pointers */ +-int *_prom_argv; ++/* the kernel command line copied from arcs_cmdline */ ++char loongson_cmdline[COMMAND_LINE_SIZE]; ++EXPORT_SYMBOL(loongson_cmdline); + + void __init prom_init_cmdline(void) + { ++ int prom_argc; ++ /* pmon passes arguments in 32bit pointers */ ++ int *_prom_argv; + int i; + long l; + +@@ -51,4 +55,26 @@ + strcat(arcs_cmdline, " root=/dev/hda1"); + + prom_init_machtype(); ++ ++ /* append machine specific command line */ ++ switch (mips_machtype) { ++ case MACH_LEMOTE_LL2F: ++ if ((strstr(arcs_cmdline, "video=")) == NULL) ++ strcat(arcs_cmdline, " video=sisfb:1360x768-16@60"); ++ break; ++ case MACH_LEMOTE_FL2F: ++ if ((strstr(arcs_cmdline, "ide_core.ignore_cable=")) == NULL) ++ strcat(arcs_cmdline, " ide_core.ignore_cable=0"); ++ break; ++ case MACH_LEMOTE_ML2F7: ++ /* Mengloong-2F has a 800x480 screen */ ++ if ((strstr(arcs_cmdline, "vga=")) == NULL) ++ strcat(arcs_cmdline, " vga=0x313"); ++ break; ++ default: ++ break; ++ } ++ ++ /* copy arcs_cmdline into loongson_cmdline */ ++ strncpy(loongson_cmdline, arcs_cmdline, COMMAND_LINE_SIZE); + } +diff -Nur linux-2.6.33/arch/mips/loongson/common/cs5536/cs5536_acc.c linux-lemote/arch/mips/loongson/common/cs5536/cs5536_acc.c +--- linux-2.6.33/arch/mips/loongson/common/cs5536/cs5536_acc.c 2010-02-24 19:52:17.000000000 +0100 ++++ linux-lemote/arch/mips/loongson/common/cs5536/cs5536_acc.c 2010-03-06 16:43:01.000000000 +0100 +@@ -5,7 +5,7 @@ + * Author : jlliu, liujl@lemote.com + * + * Copyright (C) 2009 Lemote, Inc. +- * Author: Wu Zhangjin, wuzj@lemote.com ++ * Author: Wu Zhangjin, wuzhangjin@gmail.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 +diff -Nur linux-2.6.33/arch/mips/loongson/common/cs5536/cs5536_ehci.c linux-lemote/arch/mips/loongson/common/cs5536/cs5536_ehci.c +--- linux-2.6.33/arch/mips/loongson/common/cs5536/cs5536_ehci.c 2010-02-24 19:52:17.000000000 +0100 ++++ linux-lemote/arch/mips/loongson/common/cs5536/cs5536_ehci.c 2010-03-06 16:43:01.000000000 +0100 +@@ -5,7 +5,7 @@ + * Author : jlliu, liujl@lemote.com + * + * Copyright (C) 2009 Lemote, Inc. +- * Author: Wu Zhangjin, wuzj@lemote.com ++ * Author: Wu Zhangjin, wuzhangjin@gmail.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 +diff -Nur linux-2.6.33/arch/mips/loongson/common/cs5536/cs5536_ide.c linux-lemote/arch/mips/loongson/common/cs5536/cs5536_ide.c +--- linux-2.6.33/arch/mips/loongson/common/cs5536/cs5536_ide.c 2010-02-24 19:52:17.000000000 +0100 ++++ linux-lemote/arch/mips/loongson/common/cs5536/cs5536_ide.c 2010-03-06 16:43:01.000000000 +0100 +@@ -5,7 +5,7 @@ + * Author : jlliu, liujl@lemote.com + * + * Copyright (C) 2009 Lemote, Inc. +- * Author: Wu Zhangjin, wuzj@lemote.com ++ * Author: Wu Zhangjin, wuzhangjin@gmail.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 +diff -Nur linux-2.6.33/arch/mips/loongson/common/cs5536/cs5536_isa.c linux-lemote/arch/mips/loongson/common/cs5536/cs5536_isa.c +--- linux-2.6.33/arch/mips/loongson/common/cs5536/cs5536_isa.c 2010-02-24 19:52:17.000000000 +0100 ++++ linux-lemote/arch/mips/loongson/common/cs5536/cs5536_isa.c 2010-03-06 16:43:01.000000000 +0100 +@@ -5,7 +5,7 @@ + * Author : jlliu, liujl@lemote.com + * + * Copyright (C) 2009 Lemote, Inc. +- * Author: Wu Zhangjin, wuzj@lemote.com ++ * Author: Wu Zhangjin, wuzhangjin@gmail.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 +diff -Nur linux-2.6.33/arch/mips/loongson/common/cs5536/cs5536_mfgpt.c linux-lemote/arch/mips/loongson/common/cs5536/cs5536_mfgpt.c +--- linux-2.6.33/arch/mips/loongson/common/cs5536/cs5536_mfgpt.c 2010-02-24 19:52:17.000000000 +0100 ++++ linux-lemote/arch/mips/loongson/common/cs5536/cs5536_mfgpt.c 2010-03-06 16:43:01.000000000 +0100 +@@ -5,7 +5,7 @@ + * Author: Yanhua, yanh@lemote.com + * + * Copyright (C) 2009 Lemote Inc. +- * Author: Wu zhangjin, wuzj@lemote.com ++ * Author: Wu zhangjin, wuzhangjin@gmail.com + * + * Reference: AMD Geode(TM) CS5536 Companion Device Data Book + * +diff -Nur linux-2.6.33/arch/mips/loongson/common/cs5536/cs5536_ohci.c linux-lemote/arch/mips/loongson/common/cs5536/cs5536_ohci.c +--- linux-2.6.33/arch/mips/loongson/common/cs5536/cs5536_ohci.c 2010-02-24 19:52:17.000000000 +0100 ++++ linux-lemote/arch/mips/loongson/common/cs5536/cs5536_ohci.c 2010-03-06 16:43:01.000000000 +0100 +@@ -5,7 +5,7 @@ + * Author : jlliu, liujl@lemote.com + * + * Copyright (C) 2009 Lemote, Inc. +- * Author: Wu Zhangjin, wuzj@lemote.com ++ * Author: Wu Zhangjin, wuzhangjin@gmail.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 +diff -Nur linux-2.6.33/arch/mips/loongson/common/cs5536/cs5536_pci.c linux-lemote/arch/mips/loongson/common/cs5536/cs5536_pci.c +--- linux-2.6.33/arch/mips/loongson/common/cs5536/cs5536_pci.c 2010-02-24 19:52:17.000000000 +0100 ++++ linux-lemote/arch/mips/loongson/common/cs5536/cs5536_pci.c 2010-03-06 16:43:01.000000000 +0100 +@@ -5,7 +5,7 @@ + * Author : jlliu, liujl@lemote.com + * + * Copyright (C) 2009 Lemote, Inc. +- * Author: Wu Zhangjin, wuzj@lemote.com ++ * Author: Wu Zhangjin, wuzhangjin@gmail.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 +diff -Nur linux-2.6.33/arch/mips/loongson/common/early_printk.c linux-lemote/arch/mips/loongson/common/early_printk.c +--- linux-2.6.33/arch/mips/loongson/common/early_printk.c 2010-02-24 19:52:17.000000000 +0100 ++++ linux-lemote/arch/mips/loongson/common/early_printk.c 2010-03-06 16:43:01.000000000 +0100 +@@ -2,7 +2,7 @@ + * + * Copyright (c) 2009 Philippe Vachon <philippe@cowpig.ca> + * Copyright (c) 2009 Lemote Inc. +- * Author: Wu Zhangjin, wuzj@lemote.com ++ * Author: Wu Zhangjin, wuzhangjin@gmail.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 +diff -Nur linux-2.6.33/arch/mips/loongson/common/env.c linux-lemote/arch/mips/loongson/common/env.c +--- linux-2.6.33/arch/mips/loongson/common/env.c 2010-02-24 19:52:17.000000000 +0100 ++++ linux-lemote/arch/mips/loongson/common/env.c 2010-03-06 16:43:01.000000000 +0100 +@@ -9,8 +9,8 @@ + * Copyright (C) 2007 Lemote Inc. & Insititute of Computing Technology + * Author: Fuxin Zhang, zhangfx@lemote.com + * +- * Copyright (C) 2009 Lemote Inc. & Insititute of Computing Technology +- * Author: Wu Zhangjin, wuzj@lemote.com ++ * Copyright (C) 2009 Lemote Inc. ++ * Author: Wu Zhangjin, wuzhangjin@gmail.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 +@@ -23,13 +23,10 @@ + + #include <loongson.h> + +-unsigned long bus_clock, cpu_clock_freq; ++unsigned long cpu_clock_freq; + EXPORT_SYMBOL(cpu_clock_freq); + unsigned long memsize, highmemsize; + +-/* pmon passes arguments in 32bit pointers */ +-int *_prom_envp; +- + #define parse_even_earlier(res, option, p) \ + do { \ + if (strncmp(option, (char *)p, strlen(option)) == 0) \ +@@ -39,6 +36,10 @@ + + void __init prom_init_env(void) + { ++ /* pmon passes arguments in 32bit pointers */ ++ int *_prom_envp; ++ unsigned long bus_clock; ++ unsigned int processor_id; + long l; + + /* firmware arguments are initialized in head.S */ +@@ -55,6 +56,22 @@ + } + if (memsize == 0) + memsize = 256; ++ if (bus_clock == 0) ++ bus_clock = 66000000; ++ if (cpu_clock_freq == 0) { ++ processor_id = (¤t_cpu_data)->processor_id; ++ switch (processor_id & PRID_REV_MASK) { ++ case PRID_REV_LOONGSON2E: ++ cpu_clock_freq = 533080000; ++ break; ++ case PRID_REV_LOONGSON2F: ++ cpu_clock_freq = 797000000; ++ break; ++ default: ++ cpu_clock_freq = 100000000; ++ break; ++ } ++ } + + pr_info("busclock=%ld, cpuclock=%ld, memsize=%ld, highmemsize=%ld\n", + bus_clock, cpu_clock_freq, memsize, highmemsize); +diff -Nur linux-2.6.33/arch/mips/loongson/common/init.c linux-lemote/arch/mips/loongson/common/init.c +--- linux-2.6.33/arch/mips/loongson/common/init.c 2010-02-24 19:52:17.000000000 +0100 ++++ linux-lemote/arch/mips/loongson/common/init.c 2010-03-06 16:43:01.000000000 +0100 +@@ -1,6 +1,6 @@ + /* + * Copyright (C) 2009 Lemote Inc. +- * Author: Wu Zhangjin, wuzj@lemote.com ++ * Author: Wu Zhangjin, wuzhangjin@gmail.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 +diff -Nur linux-2.6.33/arch/mips/loongson/common/machtype.c linux-lemote/arch/mips/loongson/common/machtype.c +--- linux-2.6.33/arch/mips/loongson/common/machtype.c 2010-02-24 19:52:17.000000000 +0100 ++++ linux-lemote/arch/mips/loongson/common/machtype.c 2010-03-06 16:43:01.000000000 +0100 +@@ -1,6 +1,6 @@ + /* +- * Copyright (C) 2009 Lemote Inc. & Insititute of Computing Technology +- * Author: Wu Zhangjin, wuzj@lemote.com ++ * Copyright (C) 2009 Lemote Inc. ++ * Author: Wu Zhangjin, wuzhangjin@gmail.com + * + * Copyright (c) 2009 Zhang Le <r0bertz@gentoo.org> + * +@@ -35,6 +35,10 @@ + return system_types[mips_machtype]; + } + ++void __weak __init mach_prom_init_machtype(void) ++{ ++} ++ + void __init prom_init_machtype(void) + { + char *p, str[MACHTYPE_LEN]; +@@ -43,8 +47,10 @@ + mips_machtype = LOONGSON_MACHTYPE; + + p = strstr(arcs_cmdline, "machtype="); +- if (!p) ++ if (!p) { ++ mach_prom_init_machtype(); + return; ++ } + p += strlen("machtype="); + strncpy(str, p, MACHTYPE_LEN); + p = strstr(str, " "); +diff -Nur linux-2.6.33/arch/mips/loongson/common/Makefile linux-lemote/arch/mips/loongson/common/Makefile +--- linux-2.6.33/arch/mips/loongson/common/Makefile 2010-02-24 19:52:17.000000000 +0100 ++++ linux-lemote/arch/mips/loongson/common/Makefile 2010-03-06 16:43:01.000000000 +0100 +@@ -23,3 +23,9 @@ + # + + obj-$(CONFIG_LOONGSON_SUSPEND) += pm.o ++ ++# Enable RTC Class support ++# ++# please enable CONFIG_RTC_DRV_CMOS ++# ++obj-$(CONFIG_RTC_DRV_CMOS) += rtc.o +diff -Nur linux-2.6.33/arch/mips/loongson/common/mem.c linux-lemote/arch/mips/loongson/common/mem.c +--- linux-2.6.33/arch/mips/loongson/common/mem.c 2010-02-24 19:52:17.000000000 +0100 ++++ linux-lemote/arch/mips/loongson/common/mem.c 2010-03-06 16:43:01.000000000 +0100 +@@ -16,10 +16,11 @@ + + void __init prom_init_memory(void) + { +- add_memory_region(0x0, (memsize << 20), BOOT_MEM_RAM); ++ add_memory_region(0x0, (memsize << 20), BOOT_MEM_RAM); ++ ++ add_memory_region(memsize << 20, LOONGSON_PCI_MEM_START - (memsize << ++ 20), BOOT_MEM_RESERVED); + +- add_memory_region(memsize << 20, LOONGSON_PCI_MEM_START - (memsize << +- 20), BOOT_MEM_RESERVED); + #ifdef CONFIG_CPU_SUPPORTS_ADDRWINCFG + { + int bit; +diff -Nur linux-2.6.33/arch/mips/loongson/common/mtd.c linux-lemote/arch/mips/loongson/common/mtd.c +--- linux-2.6.33/arch/mips/loongson/common/mtd.c 1970-01-01 01:00:00.000000000 +0100 ++++ linux-lemote/arch/mips/loongson/common/mtd.c 2010-03-06 16:43:01.000000000 +0100 +@@ -0,0 +1,91 @@ ++/* ++ * Driver for flushing/dumping ROM of PMON on loongson family machines ++ * ++ * Copyright (C) 2008-2009 Lemote Inc. ++ * Author: Yan Hua <yanh@lemote.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. ++ */ ++ ++#include <linux/module.h> ++#include <linux/types.h> ++#include <linux/kernel.h> ++#include <linux/init.h> ++#include <linux/mtd/mtd.h> ++#include <linux/mtd/map.h> ++#include <linux/mtd/partitions.h> ++ ++#include <asm/io.h> ++ ++#include <loongson.h> ++ ++#define FLASH_PHYS_ADDR LOONGSON_BOOT_BASE ++#define FLASH_SIZE 0x080000 ++ ++#define FLASH_PARTITION0_ADDR 0x00000000 ++#define FLASH_PARTITION0_SIZE 0x00080000 ++ ++struct map_info flash_map = { ++ .name = "flash device", ++ .size = FLASH_SIZE, ++ .bankwidth = 1, ++}; ++ ++struct mtd_partition flash_parts[] = { ++ { ++ .name = "Bootloader", ++ .offset = FLASH_PARTITION0_ADDR, ++ .size = FLASH_PARTITION0_SIZE}, ++}; ++ ++#define PARTITION_COUNT ARRAY_SIZE(flash_parts) ++ ++static struct mtd_info *mymtd; ++ ++int __init init_flash(void) ++{ ++ printk(KERN_NOTICE "flash device: %x at %x\n", ++ FLASH_SIZE, FLASH_PHYS_ADDR); ++ ++ flash_map.phys = FLASH_PHYS_ADDR; ++ flash_map.virt = ioremap(FLASH_PHYS_ADDR, FLASH_SIZE); ++ ++ if (!flash_map.virt) { ++ printk(KERN_NOTICE "Failed to ioremap\n"); ++ return -EIO; ++ } ++ ++ simple_map_init(&flash_map); ++ ++ mymtd = do_map_probe("cfi_probe", &flash_map); ++ if (mymtd) { ++ add_mtd_partitions(mymtd, flash_parts, PARTITION_COUNT); ++ printk(KERN_NOTICE "pmon flash device initialized\n"); ++ return 0; ++ } ++ ++ iounmap((void *)flash_map.virt); ++ return -ENXIO; ++} ++ ++static void __exit cleanup_flash(void) ++{ ++ if (mymtd) { ++ del_mtd_partitions(mymtd); ++ map_destroy(mymtd); ++ } ++ if (flash_map.virt) { ++ iounmap((void *)flash_map.virt); ++ flash_map.virt = 0; ++ } ++} ++ ++module_init(init_flash); ++module_exit(cleanup_flash); ++ ++MODULE_LICENSE("GPL"); ++MODULE_AUTHOR("Yanhua <yanh@lemote.com>"); ++MODULE_DESCRIPTION("MTD driver for pmon flushing/dumping"); +diff -Nur linux-2.6.33/arch/mips/loongson/common/platform.c linux-lemote/arch/mips/loongson/common/platform.c +--- linux-2.6.33/arch/mips/loongson/common/platform.c 2010-02-24 19:52:17.000000000 +0100 ++++ linux-lemote/arch/mips/loongson/common/platform.c 2010-03-06 16:43:01.000000000 +0100 +@@ -1,6 +1,6 @@ + /* + * Copyright (C) 2009 Lemote Inc. +- * Author: Wu Zhangjin, wuzj@lemote.com ++ * Author: Wu Zhangjin, wuzhangjin@gmail.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 +diff -Nur linux-2.6.33/arch/mips/loongson/common/pm.c linux-lemote/arch/mips/loongson/common/pm.c +--- linux-2.6.33/arch/mips/loongson/common/pm.c 2010-02-24 19:52:17.000000000 +0100 ++++ linux-lemote/arch/mips/loongson/common/pm.c 2010-03-06 16:43:01.000000000 +0100 +@@ -2,7 +2,7 @@ + * loongson-specific suspend support + * + * Copyright (C) 2009 Lemote Inc. +- * Author: Wu Zhangjin <wuzj@lemote.com> ++ * Author: Wu Zhangjin <wuzhangjin@gmail.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 +diff -Nur linux-2.6.33/arch/mips/loongson/common/reset.c linux-lemote/arch/mips/loongson/common/reset.c +--- linux-2.6.33/arch/mips/loongson/common/reset.c 2010-02-24 19:52:17.000000000 +0100 ++++ linux-lemote/arch/mips/loongson/common/reset.c 2010-03-06 16:43:01.000000000 +0100 +@@ -6,8 +6,8 @@ + * + * Copyright (C) 2007 Lemote, Inc. & Institute of Computing Technology + * Author: Fuxin Zhang, zhangfx@lemote.com +- * Copyright (C) 2009 Lemote, Inc. & Institute of Computing Technology +- * Author: Zhangjin Wu, wuzj@lemote.com ++ * Copyright (C) 2009 Lemote, Inc. ++ * Author: Zhangjin Wu, wuzhangjin@gmail.com + */ + #include <linux/init.h> + #include <linux/pm.h> +@@ -21,22 +21,39 @@ + /* do preparation for reboot */ + mach_prepare_reboot(); + +- /* reboot via jumping to boot base address */ ++ /* reboot via jumping to boot base address ++ * ++ * ".set noat" and ".set at" are used to ensure the address not ++ * polluted by the binutils patch. the patch will try to change the ++ * jumping address to "addr & 0xcfffffff" via the at register, which is ++ * really wrong for 0xbfc00000: ++ */ ++ ++ __asm__ __volatile__(".set noat\n"); + ((void (*)(void))ioremap_nocache(LOONGSON_BOOT_BASE, 4)) (); ++ __asm__ __volatile__(".set at\n"); + } + +-static void loongson_halt(void) ++static void loongson_poweroff(void) + { + mach_prepare_shutdown(); +- while (1) +- ; ++ unreachable(); ++} ++ ++static void loongson_halt(void) ++{ ++ pr_notice("** You can safely turn off the power ** !\n"); ++ while (1) { ++ if (cpu_wait) ++ cpu_wait(); ++ } + } + + static int __init mips_reboot_setup(void) + { + _machine_restart = loongson_restart; + _machine_halt = loongson_halt; +- pm_power_off = loongson_halt; ++ pm_power_off = loongson_poweroff; + + return 0; + } +diff -Nur linux-2.6.33/arch/mips/loongson/common/rtc.c linux-lemote/arch/mips/loongson/common/rtc.c +--- linux-2.6.33/arch/mips/loongson/common/rtc.c 1970-01-01 01:00:00.000000000 +0100 ++++ linux-lemote/arch/mips/loongson/common/rtc.c 2010-03-06 16:43:01.000000000 +0100 +@@ -0,0 +1,43 @@ ++/* ++ * Registration of Loongson RTC platform device. ++ * ++ * Copyright (C) 2007 Yoichi Yuasa <yoichi_yuasa@tripeaks.co.jp> ++ * Copyright (C) 2009 Wu Zhangjin <wuzhangjin@gmail.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. ++ */ ++ ++#include <linux/init.h> ++#include <linux/ioport.h> ++#include <linux/mc146818rtc.h> ++#include <linux/platform_device.h> ++ ++static struct resource rtc_cmos_resource[] = { ++ { ++ .start = RTC_PORT(0), ++ .end = RTC_PORT(1), ++ .flags = IORESOURCE_IO, ++ }, ++ { ++ .start = RTC_IRQ, ++ .end = RTC_IRQ, ++ .flags = IORESOURCE_IRQ, ++ }, ++}; ++ ++static struct platform_device rtc_cmos_device = { ++ .name = "rtc_cmos", ++ .id = -1, ++ .num_resources = ARRAY_SIZE(rtc_cmos_resource), ++ .resource = rtc_cmos_resource ++}; ++ ++static __init int rtc_cmos_init(void) ++{ ++ return platform_device_register(&rtc_cmos_device); ++} ++ ++device_initcall(rtc_cmos_init); +diff -Nur linux-2.6.33/arch/mips/loongson/common/serial.c linux-lemote/arch/mips/loongson/common/serial.c +--- linux-2.6.33/arch/mips/loongson/common/serial.c 2010-02-24 19:52:17.000000000 +0100 ++++ linux-lemote/arch/mips/loongson/common/serial.c 2010-03-06 16:43:01.000000000 +0100 +@@ -7,7 +7,7 @@ + * + * Copyright (C) 2009 Lemote, Inc. + * Author: Yan hua (yanhua@lemote.com) +- * Author: Wu Zhangjin (wuzj@lemote.com) ++ * Author: Wu Zhangjin (wuzhangjin@gmail.com) + */ + + #include <linux/io.h> +diff -Nur linux-2.6.33/arch/mips/loongson/common/time.c linux-lemote/arch/mips/loongson/common/time.c +--- linux-2.6.33/arch/mips/loongson/common/time.c 2010-02-24 19:52:17.000000000 +0100 ++++ linux-lemote/arch/mips/loongson/common/time.c 2010-03-06 16:43:01.000000000 +0100 +@@ -2,8 +2,8 @@ + * Copyright (C) 2007 Lemote, Inc. & Institute of Computing Technology + * Author: Fuxin Zhang, zhangfx@lemote.com + * +- * Copyright (C) 2009 Lemote Inc. & Insititute of Computing Technology +- * Author: Wu Zhangjin, wuzj@lemote.com ++ * Copyright (C) 2009 Lemote Inc. ++ * Author: Wu Zhangjin, wuzhangjin@gmail.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 +diff -Nur linux-2.6.33/arch/mips/loongson/common/uart_base.c linux-lemote/arch/mips/loongson/common/uart_base.c +--- linux-2.6.33/arch/mips/loongson/common/uart_base.c 2010-02-24 19:52:17.000000000 +0100 ++++ linux-lemote/arch/mips/loongson/common/uart_base.c 2010-03-06 16:43:01.000000000 +0100 +@@ -1,6 +1,6 @@ + /* + * Copyright (C) 2009 Lemote Inc. +- * Author: Wu Zhangjin, wuzj@lemote.com ++ * Author: Wu Zhangjin, wuzhangjin@gmail.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 +diff -Nur linux-2.6.33/arch/mips/loongson/fuloong-2e/reset.c linux-lemote/arch/mips/loongson/fuloong-2e/reset.c +--- linux-2.6.33/arch/mips/loongson/fuloong-2e/reset.c 2010-02-24 19:52:17.000000000 +0100 ++++ linux-lemote/arch/mips/loongson/fuloong-2e/reset.c 2010-03-06 16:43:01.000000000 +0100 +@@ -1,8 +1,8 @@ + /* Board-specific reboot/shutdown routines + * Copyright (c) 2009 Philippe Vachon <philippe@cowpig.ca> + * +- * Copyright (C) 2009 Lemote Inc. & Insititute of Computing Technology +- * Author: Wu Zhangjin, wuzj@lemote.com ++ * Copyright (C) 2009 Lemote Inc. ++ * Author: Wu Zhangjin, wuzhangjin@gmail.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 +diff -Nur linux-2.6.33/arch/mips/loongson/lemote-2f/ec_kb3310b.c linux-lemote/arch/mips/loongson/lemote-2f/ec_kb3310b.c +--- linux-2.6.33/arch/mips/loongson/lemote-2f/ec_kb3310b.c 2010-02-24 19:52:17.000000000 +0100 ++++ linux-lemote/arch/mips/loongson/lemote-2f/ec_kb3310b.c 2010-03-06 16:43:01.000000000 +0100 +@@ -14,7 +14,7 @@ + #include <linux/spinlock.h> + #include <linux/delay.h> + +-#include "ec_kb3310b.h" ++#include <ec_kb3310b.h> + + static DEFINE_SPINLOCK(index_access_lock); + static DEFINE_SPINLOCK(port_access_lock); +@@ -76,12 +76,9 @@ + } + + if (timeout <= 0) { +- printk(KERN_ERR "%s: deadable error : timeout...\n", __func__); ++ pr_err("%s: deadable error : timeout...\n", __func__); + ret = -EINVAL; +- } else +- printk(KERN_INFO +- "(%x/%d)ec issued command %d status : 0x%x\n", +- timeout, EC_CMD_TIMEOUT - timeout, cmd, status); ++ } + + spin_unlock_irqrestore(&port_access_lock, flags); + +@@ -118,8 +115,7 @@ + udelay(EC_REG_DELAY); + } + if (timeout <= 0) { +- pr_info("%s: get event number timeout.\n", __func__); +- ++ pr_err("%s: get event number timeout.\n", __func__); + return -EINVAL; + } + value = inb(EC_DAT_PORT); +diff -Nur linux-2.6.33/arch/mips/loongson/lemote-2f/ec_kb3310b.h linux-lemote/arch/mips/loongson/lemote-2f/ec_kb3310b.h +--- linux-2.6.33/arch/mips/loongson/lemote-2f/ec_kb3310b.h 2010-02-24 19:52:17.000000000 +0100 ++++ linux-lemote/arch/mips/loongson/lemote-2f/ec_kb3310b.h 1970-01-01 01:00:00.000000000 +0100 +@@ -1,188 +0,0 @@ +-/* +- * KB3310B Embedded Controller +- * +- * Copyright (C) 2008 Lemote Inc. +- * Author: liujl <liujl@lemote.com>, 2008-03-14 +- * +- * This program is free software; you can redistribute it and/or modify +- * it under the terms of the GNU General Public License as published by +- * the Free Software Foundation; either version 2 of the License, or +- * (at your option) any later version. +- */ +- +-#ifndef _EC_KB3310B_H +-#define _EC_KB3310B_H +- +-extern unsigned char ec_read(unsigned short addr); +-extern void ec_write(unsigned short addr, unsigned char val); +-extern int ec_query_seq(unsigned char cmd); +-extern int ec_query_event_num(void); +-extern int ec_get_event_num(void); +- +-typedef int (*sci_handler) (int status); +-extern sci_handler yeeloong_report_lid_status; +- +-#define SCI_IRQ_NUM 0x0A +- +-/* +- * The following registers are determined by the EC index configuration. +- * 1, fill the PORT_HIGH as EC register high part. +- * 2, fill the PORT_LOW as EC register low part. +- * 3, fill the PORT_DATA as EC register write data or get the data from it. +- */ +-#define EC_IO_PORT_HIGH 0x0381 +-#define EC_IO_PORT_LOW 0x0382 +-#define EC_IO_PORT_DATA 0x0383 +- +-/* +- * EC delay time is 500us for register and status access +- */ +-#define EC_REG_DELAY 500 /* unit : us */ +-#define EC_CMD_TIMEOUT 0x1000 +- +-/* +- * EC access port for SCI communication +- */ +-#define EC_CMD_PORT 0x66 +-#define EC_STS_PORT 0x66 +-#define EC_DAT_PORT 0x62 +-#define CMD_INIT_IDLE_MODE 0xdd +-#define CMD_EXIT_IDLE_MODE 0xdf +-#define CMD_INIT_RESET_MODE 0xd8 +-#define CMD_REBOOT_SYSTEM 0x8c +-#define CMD_GET_EVENT_NUM 0x84 +-#define CMD_PROGRAM_PIECE 0xda +- +-/* temperature & fan registers */ +-#define REG_TEMPERATURE_VALUE 0xF458 +-#define REG_FAN_AUTO_MAN_SWITCH 0xF459 +-#define BIT_FAN_AUTO 0 +-#define BIT_FAN_MANUAL 1 +-#define REG_FAN_CONTROL 0xF4D2 +-#define BIT_FAN_CONTROL_ON (1 << 0) +-#define BIT_FAN_CONTROL_OFF (0 << 0) +-#define REG_FAN_STATUS 0xF4DA +-#define BIT_FAN_STATUS_ON (1 << 0) +-#define BIT_FAN_STATUS_OFF (0 << 0) +-#define REG_FAN_SPEED_HIGH 0xFE22 +-#define REG_FAN_SPEED_LOW 0xFE23 +-#define REG_FAN_SPEED_LEVEL 0xF4CC +-/* fan speed divider */ +-#define FAN_SPEED_DIVIDER 480000 /* (60*1000*1000/62.5/2)*/ +- +-/* battery registers */ +-#define REG_BAT_DESIGN_CAP_HIGH 0xF77D +-#define REG_BAT_DESIGN_CAP_LOW 0xF77E +-#define REG_BAT_FULLCHG_CAP_HIGH 0xF780 +-#define REG_BAT_FULLCHG_CAP_LOW 0xF781 +-#define REG_BAT_DESIGN_VOL_HIGH 0xF782 +-#define REG_BAT_DESIGN_VOL_LOW 0xF783 +-#define REG_BAT_CURRENT_HIGH 0xF784 +-#define REG_BAT_CURRENT_LOW 0xF785 +-#define REG_BAT_VOLTAGE_HIGH 0xF786 +-#define REG_BAT_VOLTAGE_LOW 0xF787 +-#define REG_BAT_TEMPERATURE_HIGH 0xF788 +-#define REG_BAT_TEMPERATURE_LOW 0xF789 +-#define REG_BAT_RELATIVE_CAP_HIGH 0xF492 +-#define REG_BAT_RELATIVE_CAP_LOW 0xF493 +-#define REG_BAT_VENDOR 0xF4C4 +-#define FLAG_BAT_VENDOR_SANYO 0x01 +-#define FLAG_BAT_VENDOR_SIMPLO 0x02 +-#define REG_BAT_CELL_COUNT 0xF4C6 +-#define FLAG_BAT_CELL_3S1P 0x03 +-#define FLAG_BAT_CELL_3S2P 0x06 +-#define REG_BAT_CHARGE 0xF4A2 +-#define FLAG_BAT_CHARGE_DISCHARGE 0x01 +-#define FLAG_BAT_CHARGE_CHARGE 0x02 +-#define FLAG_BAT_CHARGE_ACPOWER 0x00 +-#define REG_BAT_STATUS 0xF4B0 +-#define BIT_BAT_STATUS_LOW (1 << 5) +-#define BIT_BAT_STATUS_DESTROY (1 << 2) +-#define BIT_BAT_STATUS_FULL (1 << 1) +-#define BIT_BAT_STATUS_IN (1 << 0) +-#define REG_BAT_CHARGE_STATUS 0xF4B1 +-#define BIT_BAT_CHARGE_STATUS_OVERTEMP (1 << 2) +-#define BIT_BAT_CHARGE_STATUS_PRECHG (1 << 1) +-#define REG_BAT_STATE 0xF482 +-#define BIT_BAT_STATE_CHARGING (1 << 1) +-#define BIT_BAT_STATE_DISCHARGING (1 << 0) +-#define REG_BAT_POWER 0xF440 +-#define BIT_BAT_POWER_S3 (1 << 2) +-#define BIT_BAT_POWER_ON (1 << 1) +-#define BIT_BAT_POWER_ACIN (1 << 0) +- +-/* other registers */ +-/* Audio: rd/wr */ +-#define REG_AUDIO_VOLUME 0xF46C +-#define REG_AUDIO_MUTE 0xF4E7 +-#define REG_AUDIO_BEEP 0xF4D0 +-/* USB port power or not: rd/wr */ +-#define REG_USB0_FLAG 0xF461 +-#define REG_USB1_FLAG 0xF462 +-#define REG_USB2_FLAG 0xF463 +-#define BIT_USB_FLAG_ON 1 +-#define BIT_USB_FLAG_OFF 0 +-/* LID */ +-#define REG_LID_DETECT 0xF4BD +-#define BIT_LID_DETECT_ON 1 +-#define BIT_LID_DETECT_OFF 0 +-/* CRT */ +-#define REG_CRT_DETECT 0xF4AD +-#define BIT_CRT_DETECT_PLUG 1 +-#define BIT_CRT_DETECT_UNPLUG 0 +-/* LCD backlight brightness adjust: 9 levels */ +-#define REG_DISPLAY_BRIGHTNESS 0xF4F5 +-/* Black screen Status */ +-#define BIT_DISPLAY_LCD_ON 1 +-#define BIT_DISPLAY_LCD_OFF 0 +-/* LCD backlight control: off/restore */ +-#define REG_BACKLIGHT_CTRL 0xF7BD +-#define BIT_BACKLIGHT_ON 1 +-#define BIT_BACKLIGHT_OFF 0 +-/* Reset the machine auto-clear: rd/wr */ +-#define REG_RESET 0xF4EC +-#define BIT_RESET_ON 1 +-/* Light the led: rd/wr */ +-#define REG_LED 0xF4C8 +-#define BIT_LED_RED_POWER (1 << 0) +-#define BIT_LED_ORANGE_POWER (1 << 1) +-#define BIT_LED_GREEN_CHARGE (1 << 2) +-#define BIT_LED_RED_CHARGE (1 << 3) +-#define BIT_LED_NUMLOCK (1 << 4) +-/* Test led mode, all led on/off */ +-#define REG_LED_TEST 0xF4C2 +-#define BIT_LED_TEST_IN 1 +-#define BIT_LED_TEST_OUT 0 +-/* Camera on/off */ +-#define REG_CAMERA_STATUS 0xF46A +-#define BIT_CAMERA_STATUS_ON 1 +-#define BIT_CAMERA_STATUS_OFF 0 +-#define REG_CAMERA_CONTROL 0xF7B7 +-#define BIT_CAMERA_CONTROL_OFF 0 +-#define BIT_CAMERA_CONTROL_ON 1 +-/* Wlan Status */ +-#define REG_WLAN 0xF4FA +-#define BIT_WLAN_ON 1 +-#define BIT_WLAN_OFF 0 +-#define REG_DISPLAY_LCD 0xF79F +- +-/* SCI Event Number from EC */ +-enum { +- EVENT_LID = 0x23, /* LID open/close */ +- EVENT_DISPLAY_TOGGLE, /* Fn+F3 for display switch */ +- EVENT_SLEEP, /* Fn+F1 for entering sleep mode */ +- EVENT_OVERTEMP, /* Over-temperature happened */ +- EVENT_CRT_DETECT, /* CRT is connected */ +- EVENT_CAMERA, /* Camera on/off */ +- EVENT_USB_OC2, /* USB2 Over Current occurred */ +- EVENT_USB_OC0, /* USB0 Over Current occurred */ +- EVENT_BLACK_SCREEN, /* Turn on/off backlight */ +- EVENT_AUDIO_MUTE, /* Mute on/off */ +- EVENT_DISPLAY_BRIGHTNESS,/* LCD backlight brightness adjust */ +- EVENT_AC_BAT, /* AC & Battery relative issue */ +- EVENT_AUDIO_VOLUME, /* Volume adjust */ +- EVENT_WLAN, /* Wlan on/off */ +- EVENT_END +-}; +- +-#endif /* !_EC_KB3310B_H */ +diff -Nur linux-2.6.33/arch/mips/loongson/lemote-2f/machtype.c linux-lemote/arch/mips/loongson/lemote-2f/machtype.c +--- linux-2.6.33/arch/mips/loongson/lemote-2f/machtype.c 1970-01-01 01:00:00.000000000 +0100 ++++ linux-lemote/arch/mips/loongson/lemote-2f/machtype.c 2010-03-06 16:43:01.000000000 +0100 +@@ -0,0 +1,45 @@ ++/* ++ * Copyright (C) 2009 Lemote Inc. ++ * Author: Wu Zhangjin, wuzhangjin@gmail.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. ++ */ ++#include <asm/bootinfo.h> ++ ++#include <loongson.h> ++ ++void __init mach_prom_init_machtype(void) ++{ ++ /* We share the same kernel image file among Lemote 2F family ++ * of machines, and provide the machtype= kernel command line ++ * to users to indicate their machine, this command line will ++ * be passed by the latest PMON automatically. and fortunately, ++ * up to now, we can get the machine type from the PMON_VER= ++ * commandline directly except the NAS machine, In the old ++ * machines, this will help the users a lot. ++ * ++ * If no "machtype=" passed, get machine type from "PMON_VER=". ++ * PMON_VER=LM8089 Lemote 8.9'' netbook ++ * LM8101 Lemote 10.1'' netbook ++ * (The above two netbooks have the same kernel support) ++ * LM6XXX Lemote FuLoong(2F) box series ++ * LM9XXX Lemote LynLoong PC series ++ */ ++ if (strstr(arcs_cmdline, "PMON_VER=LM")) { ++ if (strstr(arcs_cmdline, "PMON_VER=LM8")) ++ mips_machtype = MACH_LEMOTE_YL2F89; ++ else if (strstr(arcs_cmdline, "PMON_VER=LM6")) ++ mips_machtype = MACH_LEMOTE_FL2F; ++ else if (strstr(arcs_cmdline, "PMON_VER=LM9")) ++ mips_machtype = MACH_LEMOTE_LL2F; ++ else ++ mips_machtype = MACH_LEMOTE_NAS; ++ ++ strcat(arcs_cmdline, " machtype="); ++ strcat(arcs_cmdline, get_system_type()); ++ strcat(arcs_cmdline, " "); ++ } ++} +diff -Nur linux-2.6.33/arch/mips/loongson/lemote-2f/Makefile linux-lemote/arch/mips/loongson/lemote-2f/Makefile +--- linux-2.6.33/arch/mips/loongson/lemote-2f/Makefile 2010-02-24 19:52:17.000000000 +0100 ++++ linux-lemote/arch/mips/loongson/lemote-2f/Makefile 2010-03-06 16:43:01.000000000 +0100 +@@ -2,7 +2,7 @@ + # Makefile for lemote loongson2f family machines + # + +-obj-y += irq.o reset.o ec_kb3310b.o ++obj-y += machtype.o irq.o reset.o ec_kb3310b.o platform.o + + # + # Suspend Support +diff -Nur linux-2.6.33/arch/mips/loongson/lemote-2f/platform.c linux-lemote/arch/mips/loongson/lemote-2f/platform.c +--- linux-2.6.33/arch/mips/loongson/lemote-2f/platform.c 1970-01-01 01:00:00.000000000 +0100 ++++ linux-lemote/arch/mips/loongson/lemote-2f/platform.c 2010-03-06 16:43:01.000000000 +0100 +@@ -0,0 +1,48 @@ ++/* ++ * Copyright (C) 2009 Lemote Inc. ++ * Author: Wu Zhangjin, wuzhangjin@gmail.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. ++ */ ++ ++#include <linux/err.h> ++#include <linux/platform_device.h> ++ ++#include <asm/bootinfo.h> ++ ++static struct platform_device yeeloong_pdev = { ++ .name = "yeeloong_laptop", ++ .id = -1, ++}; ++ ++static struct platform_device lynloong_pdev = { ++ .name = "lynloong_pc", ++ .id = -1, ++}; ++ ++static int __init lemote2f_platform_init(void) ++{ ++ struct platform_device *pdev = NULL; ++ ++ switch (mips_machtype) { ++ case MACH_LEMOTE_YL2F89: ++ pdev = &yeeloong_pdev; ++ break; ++ case MACH_LEMOTE_LL2F: ++ pdev = &lynloong_pdev; ++ break; ++ default: ++ break; ++ ++ } ++ ++ if (pdev != NULL) ++ return platform_device_register(pdev); ++ ++ return -ENODEV; ++} ++ ++arch_initcall(lemote2f_platform_init); +diff -Nur linux-2.6.33/arch/mips/loongson/lemote-2f/pm.c linux-lemote/arch/mips/loongson/lemote-2f/pm.c +--- linux-2.6.33/arch/mips/loongson/lemote-2f/pm.c 2010-02-24 19:52:17.000000000 +0100 ++++ linux-lemote/arch/mips/loongson/lemote-2f/pm.c 2010-03-06 16:43:01.000000000 +0100 +@@ -2,7 +2,7 @@ + * Lemote loongson2f family machines' specific suspend support + * + * Copyright (C) 2009 Lemote Inc. +- * Author: Wu Zhangjin <wuzj@lemote.com> ++ * Author: Wu Zhangjin <wuzhangjin@gmail.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 +@@ -23,7 +23,7 @@ + #include <loongson.h> + + #include <cs5536/cs5536_mfgpt.h> +-#include "ec_kb3310b.h" ++#include <ec_kb3310b.h> + + #define I8042_KBD_IRQ 1 + #define I8042_CTR_KBDINT 0x01 +@@ -100,7 +100,7 @@ + if (irq < 0) + return 0; + +- printk(KERN_INFO "%s: irq = %d\n", __func__, irq); ++ pr_info("%s: irq = %d\n", __func__, irq); + + if (irq == I8042_KBD_IRQ) + return 1; +diff -Nur linux-2.6.33/arch/mips/loongson/lemote-2f/reset.c linux-lemote/arch/mips/loongson/lemote-2f/reset.c +--- linux-2.6.33/arch/mips/loongson/lemote-2f/reset.c 2010-02-24 19:52:17.000000000 +0100 ++++ linux-lemote/arch/mips/loongson/lemote-2f/reset.c 2010-03-06 16:43:01.000000000 +0100 +@@ -3,7 +3,7 @@ + * Copyright (c) 2009 Philippe Vachon <philippe@cowpig.ca> + * + * Copyright (C) 2009 Lemote Inc. +- * Author: Wu Zhangjin, wuzj@lemote.com ++ * Author: Wu Zhangjin, wuzhangjin@gmail.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 +@@ -20,7 +20,7 @@ + #include <loongson.h> + + #include <cs5536/cs5536.h> +-#include "ec_kb3310b.h" ++#include <ec_kb3310b.h> + + static void reset_cpu(void) + { +@@ -32,6 +32,7 @@ + } + + /* reset support for fuloong2f */ ++DEFINE_SPINLOCK(msr_lock); + + static void fl2f_reboot(void) + { +@@ -46,9 +47,13 @@ + */ + { + u32 hi, lo; ++ unsigned long flags; ++ ++ spin_lock_irqsave(&msr_lock, flags); + _rdmsr(DIVIL_MSR_REG(DIVIL_SOFT_RESET), &hi, &lo); + lo |= 0x00000001; + _wrmsr(DIVIL_MSR_REG(DIVIL_SOFT_RESET), hi, lo); ++ spin_unlock_irqrestore(&msr_lock, flags); + } + } + +@@ -56,9 +61,13 @@ + { + u32 hi, lo, val; + int gpio_base; ++ unsigned long flags; + + /* get gpio base */ ++ spin_lock_irqsave(&msr_lock, flags); + _rdmsr(DIVIL_MSR_REG(DIVIL_LBAR_GPIO), &hi, &lo); ++ spin_unlock_irqrestore(&msr_lock, flags); ++ + gpio_base = lo & 0xff00; + + /* make cs5536 gpio13 output enable */ +diff -Nur linux-2.6.33/arch/mips/Makefile linux-lemote/arch/mips/Makefile +--- linux-2.6.33/arch/mips/Makefile 2010-02-24 19:52:17.000000000 +0100 ++++ linux-lemote/arch/mips/Makefile 2010-03-06 16:42:59.000000000 +0100 +@@ -135,7 +135,10 @@ + cflags-$(CONFIG_CPU_LOONGSON2E) += \ + $(call cc-option,-march=loongson2e,-march=r4600) + cflags-$(CONFIG_CPU_LOONGSON2F) += \ +- $(call cc-option,-march=loongson2f,-march=r4600) ++ $(call cc-option,-march=loongson2f,-march=r4600) \ ++ $(call as-option,-Wa$(comma)-mfix-ls2f-kernel,) \ ++ $(call as-option,-Wa$(comma)-mfix-loongson2f-nop,) \ ++ $(call as-option,-Wa$(comma)-mfix-loongson2f-jump,) + + cflags-$(CONFIG_CPU_MIPS32_R1) += $(call cc-option,-march=mips32,-mips32 -U_MIPS_ISA -D_MIPS_ISA=_MIPS_ISA_MIPS32) \ + -Wa,-mips32 -Wa,--trap +@@ -332,11 +335,11 @@ + # + # Loongson family + # +-core-$(CONFIG_MACH_LOONGSON) +=arch/mips/loongson/ ++core-$(CONFIG_MACH_LOONGSON) += arch/mips/loongson/ + cflags-$(CONFIG_MACH_LOONGSON) += -I$(srctree)/arch/mips/include/asm/mach-loongson \ + -mno-branch-likely +-load-$(CONFIG_LEMOTE_FULOONG2E) +=0xffffffff80100000 +-load-$(CONFIG_LEMOTE_MACH2F) +=0xffffffff80200000 ++load-$(CONFIG_LEMOTE_FULOONG2E) += 0xffffffff80100000 ++load-$(CONFIG_LEMOTE_MACH2F) += 0xffffffff80200000 + + # + # MIPS Malta board +diff -Nur linux-2.6.33/arch/mips/oprofile/common.c linux-lemote/arch/mips/oprofile/common.c +--- linux-2.6.33/arch/mips/oprofile/common.c 2010-02-24 19:52:17.000000000 +0100 ++++ linux-lemote/arch/mips/oprofile/common.c 2010-03-06 16:43:01.000000000 +0100 +@@ -14,9 +14,9 @@ + + #include "op_impl.h" + +-extern struct op_mips_model op_model_mipsxx_ops __attribute__((weak)); +-extern struct op_mips_model op_model_rm9000_ops __attribute__((weak)); +-extern struct op_mips_model op_model_loongson2_ops __attribute__((weak)); ++extern struct op_mips_model op_model_mipsxx_ops __weak; ++extern struct op_mips_model op_model_rm9000_ops __weak; ++extern struct op_mips_model op_model_loongson2_ops __weak; + + static struct op_mips_model *model; + +diff -Nur linux-2.6.33/arch/mips/oprofile/op_model_loongson2.c linux-lemote/arch/mips/oprofile/op_model_loongson2.c +--- linux-2.6.33/arch/mips/oprofile/op_model_loongson2.c 2010-02-24 19:52:17.000000000 +0100 ++++ linux-lemote/arch/mips/oprofile/op_model_loongson2.c 2010-03-06 16:43:01.000000000 +0100 +@@ -3,7 +3,7 @@ + * + * Copyright (C) 2009 Lemote Inc. + * Author: Yanhua <yanh@lemote.com> +- * Author: Wu Zhangjin <wuzj@lemote.com> ++ * Author: Wu Zhangjin <wuzhangjin@gmail.com> + * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file "COPYING" in the main directory of this archive +diff -Nur linux-2.6.33/arch/mips/pci/fixup-lemote2f.c linux-lemote/arch/mips/pci/fixup-lemote2f.c +--- linux-2.6.33/arch/mips/pci/fixup-lemote2f.c 2010-02-24 19:52:17.000000000 +0100 ++++ linux-lemote/arch/mips/pci/fixup-lemote2f.c 2010-03-06 16:43:01.000000000 +0100 +@@ -131,7 +131,7 @@ + + /* Serial short detect enable */ + _rdmsr(USB_MSR_REG(USB_CONFIG), &hi, &lo); +- _wrmsr(USB_MSR_REG(USB_CONFIG), (1 << 1) | (1 << 2) | (1 << 3), lo); ++ _wrmsr(USB_MSR_REG(USB_CONFIG), (1 << 1) | (1 << 3), lo); + + /* setting the USB2.0 micro frame length */ + pci_write_config_dword(pdev, PCI_EHCI_FLADJ_REG, 0x2000); +diff -Nur linux-2.6.33/arch/mips/pci/ops-loongson2.c linux-lemote/arch/mips/pci/ops-loongson2.c +--- linux-2.6.33/arch/mips/pci/ops-loongson2.c 2010-02-24 19:52:17.000000000 +0100 ++++ linux-lemote/arch/mips/pci/ops-loongson2.c 2010-03-06 16:43:01.000000000 +0100 +@@ -1,13 +1,11 @@ + /* +- * fuloong2e specific PCI support. +- * + * Copyright (C) 1999, 2000, 2004 MIPS Technologies, Inc. + * All rights reserved. + * Authors: Carsten Langgaard <carstenl@mips.com> + * Maciej W. Rozycki <macro@mips.com> + * + * Copyright (C) 2009 Lemote Inc. +- * Author: Wu Zhangjin <wuzj@lemote.com> ++ * Author: Wu Zhangjin <wuzhangjin@gmail.com> + * + * This program is free software; you can distribute it and/or modify it + * under the terms of the GNU General Public License (Version 2) as +diff -Nur linux-2.6.33/arch/mips/power/cpu.c linux-lemote/arch/mips/power/cpu.c +--- linux-2.6.33/arch/mips/power/cpu.c 2010-02-24 19:52:17.000000000 +0100 ++++ linux-lemote/arch/mips/power/cpu.c 2010-03-06 16:43:01.000000000 +0100 +@@ -3,9 +3,9 @@ + * + * Licensed under the GPLv2 + * +- * Copyright (C) 2009 Lemote Inc. & Insititute of Computing Technology ++ * Copyright (C) 2009 Lemote Inc. + * Author: Hu Hongbing <huhb@lemote.com> +- * Wu Zhangjin <wuzj@lemote.com> ++ * Wu Zhangjin <wuzhangjin@gmail.com> + */ + #include <asm/suspend.h> + #include <asm/fpu.h> +diff -Nur linux-2.6.33/arch/mips/power/hibernate.S linux-lemote/arch/mips/power/hibernate.S +--- linux-2.6.33/arch/mips/power/hibernate.S 2010-02-24 19:52:17.000000000 +0100 ++++ linux-lemote/arch/mips/power/hibernate.S 2010-03-06 16:43:01.000000000 +0100 +@@ -3,9 +3,9 @@ + * + * Licensed under the GPLv2 + * +- * Copyright (C) 2009 Lemote Inc. & Insititute of Computing Technology ++ * Copyright (C) 2009 Lemote Inc. + * Author: Hu Hongbing <huhb@lemote.com> +- * Wu Zhangjin <wuzj@lemote.com> ++ * Wu Zhangjin <wuzhangjin@gmail.com> + */ + #include <asm/asm-offsets.h> + #include <asm/page.h> +diff -Nur linux-2.6.33/arch/powerpc/include/asm/prom.h linux-lemote/arch/powerpc/include/asm/prom.h +--- linux-2.6.33/arch/powerpc/include/asm/prom.h 2010-02-24 19:52:17.000000000 +0100 ++++ linux-lemote/arch/powerpc/include/asm/prom.h 2010-03-06 16:43:03.000000000 +0100 +@@ -23,21 +23,8 @@ + #include <asm/irq.h> + #include <asm/atomic.h> + +-#define OF_ROOT_NODE_ADDR_CELLS_DEFAULT 1 +-#define OF_ROOT_NODE_SIZE_CELLS_DEFAULT 1 +- +-#define of_compat_cmp(s1, s2, l) strcasecmp((s1), (s2)) +-#define of_prop_cmp(s1, s2) strcmp((s1), (s2)) +-#define of_node_cmp(s1, s2) strcasecmp((s1), (s2)) +- +-extern struct device_node *of_chosen; +- + #define HAVE_ARCH_DEVTREE_FIXUPS + +-/* For updating the device tree at runtime */ +-extern void of_attach_node(struct device_node *); +-extern void of_detach_node(struct device_node *); +- + #ifdef CONFIG_PPC32 + /* + * PCI <-> OF matching functions +@@ -52,11 +39,6 @@ + extern void pci_create_OF_bus_map(void); + #endif + +-extern struct resource *request_OF_resource(struct device_node* node, +- int index, const char* name_postfix); +-extern int release_OF_resource(struct device_node* node, int index); +- +- + /* + * OF address retreival & translation + */ +diff -Nur linux-2.6.33/drivers/ide/ide-iops.c linux-lemote/drivers/ide/ide-iops.c +--- linux-2.6.33/drivers/ide/ide-iops.c 2010-02-24 19:52:17.000000000 +0100 ++++ linux-lemote/drivers/ide/ide-iops.c 2010-03-06 16:43:16.000000000 +0100 +@@ -27,6 +27,8 @@ + #include <asm/uaccess.h> + #include <asm/io.h> + ++#include <asm/bootinfo.h> ++ + void SELECT_MASK(ide_drive_t *drive, int mask) + { + const struct ide_port_ops *port_ops = drive->hwif->port_ops; +@@ -300,6 +302,9 @@ + { + const char **list, *m = (char *)&drive->id[ATA_ID_PROD]; + ++ if (mips_machtype != MACH_LEMOTE_YL2F89) ++ return; ++ + for (list = nien_quirk_list; *list != NULL; list++) + if (strstr(m, *list) != NULL) { + drive->dev_flags |= IDE_DFLAG_NIEN_QUIRK; +diff -Nur linux-2.6.33/drivers/net/wireless/Kconfig linux-lemote/drivers/net/wireless/Kconfig +--- linux-2.6.33/drivers/net/wireless/Kconfig 2010-02-24 19:52:17.000000000 +0100 ++++ linux-lemote/drivers/net/wireless/Kconfig 2010-03-06 16:43:20.000000000 +0100 +@@ -267,7 +267,7 @@ + + config RTL8187 + tristate "Realtek 8187 and 8187B USB support" +- depends on MAC80211 && USB ++ depends on MAC80211 && USB && !LEMOTE_MACH2F + select EEPROM_93CX6 + ---help--- + This is a driver for RTL8187 and RTL8187B based cards. +@@ -294,6 +294,19 @@ + depends on RTL8187 && MAC80211_LEDS && (LEDS_CLASS = y || LEDS_CLASS = RTL8187) + default y + ++config RTL8187B ++ tristate "Realtek 8187B wifi support for yeeloong2f laptop" ++ depends on MAC80211 && USB && LEMOTE_MACH2F ++ depends on RFKILL || !RFKILL ++ select CRYPTO ++ select WIRELESS_EXT ++ select WEXT_PRIV ++ ---help--- ++ This is a driver for RTL8187B based cards, this driver is especially ++ for yeeloon2f laptop. ++ ++ Thanks to Realtek for their support! ++ + config ADM8211 + tristate "ADMtek ADM8211 support" + depends on MAC80211 && PCI && EXPERIMENTAL +diff -Nur linux-2.6.33/drivers/net/wireless/Makefile linux-lemote/drivers/net/wireless/Makefile +--- linux-2.6.33/drivers/net/wireless/Makefile 2010-02-24 19:52:17.000000000 +0100 ++++ linux-lemote/drivers/net/wireless/Makefile 2010-03-06 16:43:20.000000000 +0100 +@@ -24,6 +24,7 @@ + obj-$(CONFIG_ZD1211RW) += zd1211rw/ + obj-$(CONFIG_RTL8180) += rtl818x/ + obj-$(CONFIG_RTL8187) += rtl818x/ ++obj-$(CONFIG_RTL8187B) += rtl8187b/ + + # 16-bit wireless PCMCIA client drivers + obj-$(CONFIG_PCMCIA_RAYCS) += ray_cs.o +diff -Nur linux-2.6.33/drivers/net/wireless/rtl8187b/dot11d.h linux-lemote/drivers/net/wireless/rtl8187b/dot11d.h +--- linux-2.6.33/drivers/net/wireless/rtl8187b/dot11d.h 1970-01-01 01:00:00.000000000 +0100 ++++ linux-lemote/drivers/net/wireless/rtl8187b/dot11d.h 2010-03-06 16:43:22.000000000 +0100 +@@ -0,0 +1,102 @@ ++#ifndef __INC_DOT11D_H
++#define __INC_DOT11D_H
++
++#include "ieee80211/ieee80211.h"
++
++//#define ENABLE_DOT11D
++
++//#define DOT11D_MAX_CHNL_NUM 83
++
++typedef struct _CHNL_TXPOWER_TRIPLE {
++ u8 FirstChnl;
++ u8 NumChnls;
++ u8 MaxTxPowerInDbm;
++}CHNL_TXPOWER_TRIPLE, *PCHNL_TXPOWER_TRIPLE;
++
++typedef enum _DOT11D_STATE {
++ DOT11D_STATE_NONE = 0,
++ DOT11D_STATE_LEARNED,
++ DOT11D_STATE_DONE,
++}DOT11D_STATE;
++
++typedef struct _RT_DOT11D_INFO {
++ //DECLARE_RT_OBJECT(RT_DOT11D_INFO);
++
++ bool bEnabled; // dot11MultiDomainCapabilityEnabled
++
++ u16 CountryIeLen; // > 0 if CountryIeBuf[] contains valid country information element.
++ u8 CountryIeBuf[MAX_IE_LEN];
++ u8 CountryIeSrcAddr[6]; // Source AP of the country IE.
++ u8 CountryIeWatchdog;
++
++ u8 channel_map[MAX_CHANNEL_NUMBER+1]; //!!!Value 0: Invalid, 1: Valid (active scan), 2: Valid (passive scan)
++ //u8 ChnlListLen; // #Bytes valid in ChnlList[].
++ //u8 ChnlList[DOT11D_MAX_CHNL_NUM];
++ u8 MaxTxPwrDbmList[MAX_CHANNEL_NUMBER+1];
++
++ DOT11D_STATE State;
++}RT_DOT11D_INFO, *PRT_DOT11D_INFO;
++#define eqMacAddr(a,b) ( ((a)[0]==(b)[0] && (a)[1]==(b)[1] && (a)[2]==(b)[2] && (a)[3]==(b)[3] && (a)[4]==(b)[4] && (a)[5]==(b)[5]) ? 1:0 )
++#define cpMacAddr(des,src) ((des)[0]=(src)[0],(des)[1]=(src)[1],(des)[2]=(src)[2],(des)[3]=(src)[3],(des)[4]=(src)[4],(des)[5]=(src)[5])
++#define GET_DOT11D_INFO(__pIeeeDev) ((PRT_DOT11D_INFO)((__pIeeeDev)->pDot11dInfo))
++
++#define IS_DOT11D_ENABLE(__pIeeeDev) GET_DOT11D_INFO(__pIeeeDev)->bEnabled
++#define IS_COUNTRY_IE_VALID(__pIeeeDev) (GET_DOT11D_INFO(__pIeeeDev)->CountryIeLen > 0)
++
++#define IS_EQUAL_CIE_SRC(__pIeeeDev, __pTa) eqMacAddr(GET_DOT11D_INFO(__pIeeeDev)->CountryIeSrcAddr, __pTa)
++#define UPDATE_CIE_SRC(__pIeeeDev, __pTa) cpMacAddr(GET_DOT11D_INFO(__pIeeeDev)->CountryIeSrcAddr, __pTa)
++
++#define IS_COUNTRY_IE_CHANGED(__pIeeeDev, __Ie) \
++ (((__Ie).Length == 0 || (__Ie).Length != GET_DOT11D_INFO(__pIeeeDev)->CountryIeLen) ? \
++ FALSE : \
++ (!memcmp(GET_DOT11D_INFO(__pIeeeDev)->CountryIeBuf, (__Ie).Octet, (__Ie).Length)))
++
++#define CIE_WATCHDOG_TH 1
++#define GET_CIE_WATCHDOG(__pIeeeDev) GET_DOT11D_INFO(__pIeeeDev)->CountryIeWatchdog
++#define RESET_CIE_WATCHDOG(__pIeeeDev) GET_CIE_WATCHDOG(__pIeeeDev) = 0
++#define UPDATE_CIE_WATCHDOG(__pIeeeDev) ++GET_CIE_WATCHDOG(__pIeeeDev)
++
++#define IS_DOT11D_STATE_DONE(__pIeeeDev) (GET_DOT11D_INFO(__pIeeeDev)->State == DOT11D_STATE_DONE)
++
++
++void
++Dot11d_Init(
++ struct ieee80211_device *dev
++ );
++
++void
++Dot11d_Reset(
++ struct ieee80211_device *dev
++ );
++
++void
++Dot11d_UpdateCountryIe(
++ struct ieee80211_device *dev,
++ u8 * pTaddr,
++ u16 CoutryIeLen,
++ u8 * pCoutryIe
++ );
++
++u8
++DOT11D_GetMaxTxPwrInDbm(
++ struct ieee80211_device *dev,
++ u8 Channel
++ );
++
++void
++DOT11D_ScanComplete(
++ struct ieee80211_device * dev
++ );
++
++int IsLegalChannel(
++ struct ieee80211_device * dev,
++ u8 channel
++);
++
++int ToLegalChannel(
++ struct ieee80211_device * dev,
++ u8 channel
++);
++
++void dump_chnl_map(u8 * channel_map);
++#endif // #ifndef __INC_DOT11D_H
+diff -Nur linux-2.6.33/drivers/net/wireless/rtl8187b/ieee80211/arc4.c linux-lemote/drivers/net/wireless/rtl8187b/ieee80211/arc4.c +--- linux-2.6.33/drivers/net/wireless/rtl8187b/ieee80211/arc4.c 1970-01-01 01:00:00.000000000 +0100 ++++ linux-lemote/drivers/net/wireless/rtl8187b/ieee80211/arc4.c 2010-03-06 16:43:22.000000000 +0100 +@@ -0,0 +1,103 @@ ++/* ++ * Cryptographic API ++ * ++ * ARC4 Cipher Algorithm ++ * ++ * Jon Oberheide <jon@oberheide.org> ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ */ ++#include <linux/module.h> ++#include <linux/init.h> ++#include "rtl_crypto.h" ++ ++#define ARC4_MIN_KEY_SIZE 1 ++#define ARC4_MAX_KEY_SIZE 256 ++#define ARC4_BLOCK_SIZE 1 ++ ++struct arc4_ctx { ++ u8 S[256]; ++ u8 x, y; ++}; ++ ++static int arc4_set_key(void *ctx_arg, const u8 *in_key, unsigned int key_len, u32 *flags) ++{ ++ struct arc4_ctx *ctx = ctx_arg; ++ int i, j = 0, k = 0; ++ ++ ctx->x = 1; ++ ctx->y = 0; ++ ++ for(i = 0; i < 256; i++) ++ ctx->S[i] = i; ++ ++ for(i = 0; i < 256; i++) ++ { ++ u8 a = ctx->S[i]; ++ j = (j + in_key[k] + a) & 0xff; ++ ctx->S[i] = ctx->S[j]; ++ ctx->S[j] = a; ++ if(++k >= key_len) ++ k = 0; ++ } ++ ++ return 0; ++} ++ ++static void arc4_crypt(void *ctx_arg, u8 *out, const u8 *in) ++{ ++ struct arc4_ctx *ctx = ctx_arg; ++ ++ u8 *const S = ctx->S; ++ u8 x = ctx->x; ++ u8 y = ctx->y; ++ u8 a, b; ++ ++ a = S[x]; ++ y = (y + a) & 0xff; ++ b = S[y]; ++ S[x] = b; ++ S[y] = a; ++ x = (x + 1) & 0xff; ++ *out++ = *in ^ S[(a + b) & 0xff]; ++ ++ ctx->x = x; ++ ctx->y = y; ++} ++ ++static struct crypto_alg arc4_alg = { ++ .cra_name = "arc4", ++ .cra_flags = CRYPTO_ALG_TYPE_CIPHER, ++ .cra_blocksize = ARC4_BLOCK_SIZE, ++ .cra_ctxsize = sizeof(struct arc4_ctx), ++ .cra_module = THIS_MODULE, ++ .cra_list = LIST_HEAD_INIT(arc4_alg.cra_list), ++ .cra_u = { .cipher = { ++ .cia_min_keysize = ARC4_MIN_KEY_SIZE, ++ .cia_max_keysize = ARC4_MAX_KEY_SIZE, ++ .cia_setkey = arc4_set_key, ++ .cia_encrypt = arc4_crypt, ++ .cia_decrypt = arc4_crypt } } ++}; ++ ++static int __init arc4_init(void) ++{ ++ return crypto_register_alg(&arc4_alg); ++} ++ ++ ++static void __exit arc4_exit(void) ++{ ++ crypto_unregister_alg(&arc4_alg); ++} ++ ++module_init(arc4_init); ++module_exit(arc4_exit); ++ ++MODULE_LICENSE("GPL"); ++MODULE_DESCRIPTION("ARC4 Cipher Algorithm"); ++MODULE_AUTHOR("Jon Oberheide <jon@oberheide.org>"); +diff -Nur linux-2.6.33/drivers/net/wireless/rtl8187b/ieee80211/dot11d.c linux-lemote/drivers/net/wireless/rtl8187b/ieee80211/dot11d.c +--- linux-2.6.33/drivers/net/wireless/rtl8187b/ieee80211/dot11d.c 1970-01-01 01:00:00.000000000 +0100 ++++ linux-lemote/drivers/net/wireless/rtl8187b/ieee80211/dot11d.c 2010-03-06 16:43:22.000000000 +0100 +@@ -0,0 +1,244 @@ ++#ifdef ENABLE_DOT11D
++//-----------------------------------------------------------------------------
++// File:
++// Dot11d.c
++//
++// Description:
++// Implement 802.11d.
++//
++//-----------------------------------------------------------------------------
++
++#include "dot11d.h"
++
++void
++Dot11d_Init(struct ieee80211_device *ieee)
++{
++ PRT_DOT11D_INFO pDot11dInfo = GET_DOT11D_INFO(ieee);
++
++ pDot11dInfo->bEnabled = 0;
++
++ pDot11dInfo->State = DOT11D_STATE_NONE;
++ pDot11dInfo->CountryIeLen = 0;
++ memset(pDot11dInfo->channel_map, 0, MAX_CHANNEL_NUMBER+1);
++ memset(pDot11dInfo->MaxTxPwrDbmList, 0xFF, MAX_CHANNEL_NUMBER+1);
++ RESET_CIE_WATCHDOG(ieee);
++
++ //printk("Dot11d_Init()\n");
++}
++
++//
++// Description:
++// Reset to the state as we are just entering a regulatory domain.
++//
++void
++Dot11d_Reset(struct ieee80211_device *ieee)
++{
++ u32 i;
++ PRT_DOT11D_INFO pDot11dInfo = GET_DOT11D_INFO(ieee);
++
++ // Clear old channel map
++ memset(pDot11dInfo->channel_map, 0, MAX_CHANNEL_NUMBER+1);
++ memset(pDot11dInfo->MaxTxPwrDbmList, 0xFF, MAX_CHANNEL_NUMBER+1);
++ // Set new channel map
++ for (i=1; i<=11; i++) {
++ (pDot11dInfo->channel_map)[i] = 1;
++ }
++ for (i=12; i<=14; i++) {
++ (pDot11dInfo->channel_map)[i] = 2;
++ }
++
++ pDot11dInfo->State = DOT11D_STATE_NONE;
++ pDot11dInfo->CountryIeLen = 0;
++ RESET_CIE_WATCHDOG(ieee);
++
++ //printk("Dot11d_Reset()\n");
++}
++
++//
++// Description:
++// Update country IE from Beacon or Probe Resopnse
++// and configure PHY for operation in the regulatory domain.
++//
++// TODO:
++// Configure Tx power.
++//
++// Assumption:
++// 1. IS_DOT11D_ENABLE() is TRUE.
++// 2. Input IE is an valid one.
++//
++void
++Dot11d_UpdateCountryIe(
++ struct ieee80211_device *dev,
++ u8 * pTaddr,
++ u16 CoutryIeLen,
++ u8 * pCoutryIe
++ )
++{
++ PRT_DOT11D_INFO pDot11dInfo = GET_DOT11D_INFO(dev);
++ u8 i, j, NumTriples, MaxChnlNum;
++ PCHNL_TXPOWER_TRIPLE pTriple;
++
++ if((CoutryIeLen - 3)%3 != 0)
++ {
++ printk("Dot11d_UpdateCountryIe(): Invalid country IE, skip it........1\n");
++ Dot11d_Reset(dev);
++ return;
++ }
++
++ memset(pDot11dInfo->channel_map, 0, MAX_CHANNEL_NUMBER+1);
++ memset(pDot11dInfo->MaxTxPwrDbmList, 0xFF, MAX_CHANNEL_NUMBER+1);
++ MaxChnlNum = 0;
++ NumTriples = (CoutryIeLen - 3) / 3; // skip 3-byte country string.
++ pTriple = (PCHNL_TXPOWER_TRIPLE)(pCoutryIe + 3);
++ for(i = 0; i < NumTriples; i++)
++ {
++ if(MaxChnlNum >= pTriple->FirstChnl)
++ { // It is not in a monotonically increasing order, so stop processing.
++ printk("Dot11d_UpdateCountryIe(): Invalid country IE, skip it........1\n");
++ Dot11d_Reset(dev);
++ return;
++ }
++ if(MAX_CHANNEL_NUMBER < (pTriple->FirstChnl + pTriple->NumChnls))
++ { // It is not a valid set of channel id, so stop processing.
++ printk("Dot11d_UpdateCountryIe(): Invalid country IE, skip it........2\n");
++ Dot11d_Reset(dev);
++ return;
++ }
++
++ for(j = 0 ; j < pTriple->NumChnls; j++)
++ {
++ pDot11dInfo->channel_map[pTriple->FirstChnl + j] = 1;
++ pDot11dInfo->MaxTxPwrDbmList[pTriple->FirstChnl + j] = pTriple->MaxTxPowerInDbm;
++ MaxChnlNum = pTriple->FirstChnl + j;
++ }
++
++ pTriple = (PCHNL_TXPOWER_TRIPLE)((u8*)pTriple + 3);
++ }
++#if 1
++ //printk("Dot11d_UpdateCountryIe(): Channel List:\n");
++ printk("Channel List:");
++ for(i=1; i<= MAX_CHANNEL_NUMBER; i++)
++ if(pDot11dInfo->channel_map[i] > 0)
++ printk(" %d", i);
++ printk("\n");
++#endif
++
++ UPDATE_CIE_SRC(dev, pTaddr);
++
++ pDot11dInfo->CountryIeLen = CoutryIeLen;
++ memcpy(pDot11dInfo->CountryIeBuf, pCoutryIe,CoutryIeLen);
++ pDot11dInfo->State = DOT11D_STATE_LEARNED;
++}
++
++void dump_chnl_map(u8 * channel_map)
++{
++ int i;
++ printk("Channel List:");
++ for(i=1; i<= MAX_CHANNEL_NUMBER; i++)
++ if(channel_map[i] > 0)
++ printk(" %d(%d)", i, channel_map[i]);
++ printk("\n");
++}
++
++u8
++DOT11D_GetMaxTxPwrInDbm(
++ struct ieee80211_device *dev,
++ u8 Channel
++ )
++{
++ PRT_DOT11D_INFO pDot11dInfo = GET_DOT11D_INFO(dev);
++ u8 MaxTxPwrInDbm = 255;
++
++ if(MAX_CHANNEL_NUMBER < Channel)
++ {
++ printk("DOT11D_GetMaxTxPwrInDbm(): Invalid Channel\n");
++ return MaxTxPwrInDbm;
++ }
++ if(pDot11dInfo->channel_map[Channel])
++ {
++ MaxTxPwrInDbm = pDot11dInfo->MaxTxPwrDbmList[Channel];
++ }
++
++ return MaxTxPwrInDbm;
++}
++
++
++void
++DOT11D_ScanComplete(
++ struct ieee80211_device * dev
++ )
++{
++ PRT_DOT11D_INFO pDot11dInfo = GET_DOT11D_INFO(dev);
++
++ switch(pDot11dInfo->State)
++ {
++ case DOT11D_STATE_LEARNED:
++ pDot11dInfo->State = DOT11D_STATE_DONE;
++ break;
++
++ case DOT11D_STATE_DONE:
++ if( GET_CIE_WATCHDOG(dev) == 0 )
++ { // Reset country IE if previous one is gone.
++ Dot11d_Reset(dev);
++ }
++ break;
++ case DOT11D_STATE_NONE:
++ break;
++ }
++}
++
++int IsLegalChannel(
++ struct ieee80211_device * dev,
++ u8 channel
++)
++{
++ PRT_DOT11D_INFO pDot11dInfo = GET_DOT11D_INFO(dev);
++
++ if(MAX_CHANNEL_NUMBER < channel)
++ {
++ printk("IsLegalChannel(): Invalid Channel\n");
++ return 0;
++ }
++ if(pDot11dInfo->channel_map[channel] > 0)
++ return 1;
++ return 0;
++}
++
++int ToLegalChannel(
++ struct ieee80211_device * dev,
++ u8 channel
++)
++{
++ PRT_DOT11D_INFO pDot11dInfo = GET_DOT11D_INFO(dev);
++ u8 default_chn = 0;
++ u32 i = 0;
++
++ for (i=1; i<= MAX_CHANNEL_NUMBER; i++)
++ {
++ if(pDot11dInfo->channel_map[i] > 0)
++ {
++ default_chn = i;
++ break;
++ }
++ }
++
++ if(MAX_CHANNEL_NUMBER < channel)
++ {
++ printk("IsLegalChannel(): Invalid Channel\n");
++ return default_chn;
++ }
++
++ if(pDot11dInfo->channel_map[channel] > 0)
++ return channel;
++
++ return default_chn;
++}
++
++EXPORT_SYMBOL(Dot11d_Init);
++EXPORT_SYMBOL(Dot11d_Reset);
++EXPORT_SYMBOL(Dot11d_UpdateCountryIe);
++EXPORT_SYMBOL(DOT11D_GetMaxTxPwrInDbm);
++EXPORT_SYMBOL(DOT11D_ScanComplete);
++EXPORT_SYMBOL(IsLegalChannel);
++EXPORT_SYMBOL(ToLegalChannel);
++#endif
+diff -Nur linux-2.6.33/drivers/net/wireless/rtl8187b/ieee80211/dot11d.h linux-lemote/drivers/net/wireless/rtl8187b/ieee80211/dot11d.h +--- linux-2.6.33/drivers/net/wireless/rtl8187b/ieee80211/dot11d.h 1970-01-01 01:00:00.000000000 +0100 ++++ linux-lemote/drivers/net/wireless/rtl8187b/ieee80211/dot11d.h 2010-03-06 16:43:22.000000000 +0100 +@@ -0,0 +1,102 @@ ++#ifndef __INC_DOT11D_H
++#define __INC_DOT11D_H
++
++#include "ieee80211.h"
++
++//#define ENABLE_DOT11D
++
++//#define DOT11D_MAX_CHNL_NUM 83
++
++typedef struct _CHNL_TXPOWER_TRIPLE {
++ u8 FirstChnl;
++ u8 NumChnls;
++ u8 MaxTxPowerInDbm;
++}CHNL_TXPOWER_TRIPLE, *PCHNL_TXPOWER_TRIPLE;
++
++typedef enum _DOT11D_STATE {
++ DOT11D_STATE_NONE = 0,
++ DOT11D_STATE_LEARNED,
++ DOT11D_STATE_DONE,
++}DOT11D_STATE;
++
++typedef struct _RT_DOT11D_INFO {
++ //DECLARE_RT_OBJECT(RT_DOT11D_INFO);
++
++ bool bEnabled; // dot11MultiDomainCapabilityEnabled
++
++ u16 CountryIeLen; // > 0 if CountryIeBuf[] contains valid country information element.
++ u8 CountryIeBuf[MAX_IE_LEN];
++ u8 CountryIeSrcAddr[6]; // Source AP of the country IE.
++ u8 CountryIeWatchdog;
++
++ u8 channel_map[MAX_CHANNEL_NUMBER+1]; //!!!Value 0: Invalid, 1: Valid (active scan), 2: Valid (passive scan)
++ //u8 ChnlListLen; // #Bytes valid in ChnlList[].
++ //u8 ChnlList[DOT11D_MAX_CHNL_NUM];
++ u8 MaxTxPwrDbmList[MAX_CHANNEL_NUMBER+1];
++
++ DOT11D_STATE State;
++}RT_DOT11D_INFO, *PRT_DOT11D_INFO;
++#define eqMacAddr(a,b) ( ((a)[0]==(b)[0] && (a)[1]==(b)[1] && (a)[2]==(b)[2] && (a)[3]==(b)[3] && (a)[4]==(b)[4] && (a)[5]==(b)[5]) ? 1:0 )
++#define cpMacAddr(des,src) ((des)[0]=(src)[0],(des)[1]=(src)[1],(des)[2]=(src)[2],(des)[3]=(src)[3],(des)[4]=(src)[4],(des)[5]=(src)[5])
++#define GET_DOT11D_INFO(__pIeeeDev) ((PRT_DOT11D_INFO)((__pIeeeDev)->pDot11dInfo))
++
++#define IS_DOT11D_ENABLE(__pIeeeDev) GET_DOT11D_INFO(__pIeeeDev)->bEnabled
++#define IS_COUNTRY_IE_VALID(__pIeeeDev) (GET_DOT11D_INFO(__pIeeeDev)->CountryIeLen > 0)
++
++#define IS_EQUAL_CIE_SRC(__pIeeeDev, __pTa) eqMacAddr(GET_DOT11D_INFO(__pIeeeDev)->CountryIeSrcAddr, __pTa)
++#define UPDATE_CIE_SRC(__pIeeeDev, __pTa) cpMacAddr(GET_DOT11D_INFO(__pIeeeDev)->CountryIeSrcAddr, __pTa)
++
++#define IS_COUNTRY_IE_CHANGED(__pIeeeDev, __Ie) \
++ (((__Ie).Length == 0 || (__Ie).Length != GET_DOT11D_INFO(__pIeeeDev)->CountryIeLen) ? \
++ FALSE : \
++ (!memcmp(GET_DOT11D_INFO(__pIeeeDev)->CountryIeBuf, (__Ie).Octet, (__Ie).Length)))
++
++#define CIE_WATCHDOG_TH 1
++#define GET_CIE_WATCHDOG(__pIeeeDev) GET_DOT11D_INFO(__pIeeeDev)->CountryIeWatchdog
++#define RESET_CIE_WATCHDOG(__pIeeeDev) GET_CIE_WATCHDOG(__pIeeeDev) = 0
++#define UPDATE_CIE_WATCHDOG(__pIeeeDev) ++GET_CIE_WATCHDOG(__pIeeeDev)
++
++#define IS_DOT11D_STATE_DONE(__pIeeeDev) (GET_DOT11D_INFO(__pIeeeDev)->State == DOT11D_STATE_DONE)
++
++
++void
++Dot11d_Init(
++ struct ieee80211_device *dev
++ );
++
++void
++Dot11d_Reset(
++ struct ieee80211_device *dev
++ );
++
++void
++Dot11d_UpdateCountryIe(
++ struct ieee80211_device *dev,
++ u8 * pTaddr,
++ u16 CoutryIeLen,
++ u8 * pCoutryIe
++ );
++
++u8
++DOT11D_GetMaxTxPwrInDbm(
++ struct ieee80211_device *dev,
++ u8 Channel
++ );
++
++void
++DOT11D_ScanComplete(
++ struct ieee80211_device * dev
++ );
++
++int IsLegalChannel(
++ struct ieee80211_device * dev,
++ u8 channel
++);
++
++int ToLegalChannel(
++ struct ieee80211_device * dev,
++ u8 channel
++);
++
++void dump_chnl_map(u8 * channel_map);
++#endif // #ifndef __INC_DOT11D_H
+diff -Nur linux-2.6.33/drivers/net/wireless/rtl8187b/ieee80211/ieee80211_crypt.c linux-lemote/drivers/net/wireless/rtl8187b/ieee80211/ieee80211_crypt.c +--- linux-2.6.33/drivers/net/wireless/rtl8187b/ieee80211/ieee80211_crypt.c 1970-01-01 01:00:00.000000000 +0100 ++++ linux-lemote/drivers/net/wireless/rtl8187b/ieee80211/ieee80211_crypt.c 2010-03-06 16:43:22.000000000 +0100 +@@ -0,0 +1,275 @@ ++/* ++ * Host AP crypto routines ++ * ++ * Copyright (c) 2002-2003, Jouni Malinen <jkmaline@cc.hut.fi> ++ * Portions Copyright (C) 2004, Intel Corporation <jketreno@linux.intel.com> ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License version 2 as ++ * published by the Free Software Foundation. See README and COPYING for ++ * more details. ++ * ++ */ ++ ++//#include <linux/config.h> ++#include <linux/version.h> ++#include <linux/module.h> ++#include <linux/init.h> ++#include <linux/slab.h> ++#include <asm/string.h> ++#include <asm/errno.h> ++ ++#include "ieee80211.h" ++ ++MODULE_AUTHOR("Jouni Malinen"); ++MODULE_DESCRIPTION("HostAP crypto"); ++MODULE_LICENSE("GPL"); ++ ++struct ieee80211_crypto_alg { ++ struct list_head list; ++ struct ieee80211_crypto_ops *ops; ++}; ++ ++ ++struct ieee80211_crypto { ++ struct list_head algs; ++ spinlock_t lock; ++}; ++ ++static struct ieee80211_crypto *hcrypt; ++ ++void ieee80211_crypt_deinit_entries(struct ieee80211_device *ieee, ++ int force) ++{ ++ struct list_head *ptr, *n; ++ struct ieee80211_crypt_data *entry; ++ ++ for (ptr = ieee->crypt_deinit_list.next, n = ptr->next; ++ ptr != &ieee->crypt_deinit_list; ptr = n, n = ptr->next) { ++ entry = list_entry(ptr, struct ieee80211_crypt_data, list); ++ ++ if (atomic_read(&entry->refcnt) != 0 && !force) ++ continue; ++ ++ list_del(ptr); ++ ++ if (entry->ops) { ++ entry->ops->deinit(entry->priv); ++#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0) ++ module_put(entry->ops->owner); ++#else ++ __MOD_DEC_USE_COUNT(entry->ops->owner); ++#endif ++ } ++ kfree(entry); ++ } ++} ++ ++void ieee80211_crypt_deinit_handler(unsigned long data) ++{ ++ struct ieee80211_device *ieee = (struct ieee80211_device *)data; ++ unsigned long flags; ++ ++ spin_lock_irqsave(&ieee->lock, flags); ++ ieee80211_crypt_deinit_entries(ieee, 0); ++ if (!list_empty(&ieee->crypt_deinit_list)) { ++ printk(KERN_DEBUG "%s: entries remaining in delayed crypt " ++ "deletion list\n", ieee->dev->name); ++ ieee->crypt_deinit_timer.expires = jiffies + HZ; ++ add_timer(&ieee->crypt_deinit_timer); ++ } ++ spin_unlock_irqrestore(&ieee->lock, flags); ++ ++} ++ ++void ieee80211_crypt_delayed_deinit(struct ieee80211_device *ieee, ++ struct ieee80211_crypt_data **crypt) ++{ ++ struct ieee80211_crypt_data *tmp; ++ unsigned long flags; ++ ++ if (*crypt == NULL) ++ return; ++ ++ tmp = *crypt; ++ *crypt = NULL; ++ ++ /* must not run ops->deinit() while there may be pending encrypt or ++ * decrypt operations. Use a list of delayed deinits to avoid needing ++ * locking. */ ++ ++ spin_lock_irqsave(&ieee->lock, flags); ++ list_add(&tmp->list, &ieee->crypt_deinit_list); ++ if (!timer_pending(&ieee->crypt_deinit_timer)) { ++ ieee->crypt_deinit_timer.expires = jiffies + HZ; ++ add_timer(&ieee->crypt_deinit_timer); ++ } ++ spin_unlock_irqrestore(&ieee->lock, flags); ++} ++ ++int ieee80211_register_crypto_ops(struct ieee80211_crypto_ops *ops) ++{ ++ unsigned long flags; ++ struct ieee80211_crypto_alg *alg; ++ ++ if (hcrypt == NULL) ++ return -1; ++ ++ alg = kmalloc(sizeof(*alg), GFP_KERNEL); ++ if (alg == NULL) ++ return -ENOMEM; ++ ++ memset(alg, 0, sizeof(*alg)); ++ alg->ops = ops; ++ ++ spin_lock_irqsave(&hcrypt->lock, flags); ++ list_add(&alg->list, &hcrypt->algs); ++ spin_unlock_irqrestore(&hcrypt->lock, flags); ++ ++ printk(KERN_DEBUG "ieee80211_crypt: registered algorithm '%s'\n", ++ ops->name); ++ ++ return 0; ++} ++ ++int ieee80211_unregister_crypto_ops(struct ieee80211_crypto_ops *ops) ++{ ++ unsigned long flags; ++ struct list_head *ptr; ++ struct ieee80211_crypto_alg *del_alg = NULL; ++ ++ if (hcrypt == NULL) ++ return -1; ++ ++ spin_lock_irqsave(&hcrypt->lock, flags); ++ for (ptr = hcrypt->algs.next; ptr != &hcrypt->algs; ptr = ptr->next) { ++ struct ieee80211_crypto_alg *alg = ++ (struct ieee80211_crypto_alg *) ptr; ++ if (alg->ops == ops) { ++ list_del(&alg->list); ++ del_alg = alg; ++ break; ++ } ++ } ++ spin_unlock_irqrestore(&hcrypt->lock, flags); ++ ++ if (del_alg) { ++ printk(KERN_DEBUG "ieee80211_crypt: unregistered algorithm " ++ "'%s'\n", ops->name); ++ kfree(del_alg); ++ } ++ ++ return del_alg ? 0 : -1; ++} ++ ++ ++struct ieee80211_crypto_ops * ieee80211_get_crypto_ops(const char *name) ++{ ++ unsigned long flags; ++ struct list_head *ptr; ++ struct ieee80211_crypto_alg *found_alg = NULL; ++ ++ if (hcrypt == NULL) ++ return NULL; ++ ++ spin_lock_irqsave(&hcrypt->lock, flags); ++ for (ptr = hcrypt->algs.next; ptr != &hcrypt->algs; ptr = ptr->next) { ++ struct ieee80211_crypto_alg *alg = ++ (struct ieee80211_crypto_alg *) ptr; ++ if (strcmp(alg->ops->name, name) == 0) { ++ found_alg = alg; ++ break; ++ } ++ } ++ spin_unlock_irqrestore(&hcrypt->lock, flags); ++ ++ if (found_alg) ++ return found_alg->ops; ++ else ++ return NULL; ++} ++ ++ ++static void * ieee80211_crypt_null_init(int keyidx) { return (void *) 1; } ++static void ieee80211_crypt_null_deinit(void *priv) {} ++ ++static struct ieee80211_crypto_ops ieee80211_crypt_null = { ++ .name = "NULL", ++ .init = ieee80211_crypt_null_init, ++ .deinit = ieee80211_crypt_null_deinit, ++ .encrypt_mpdu = NULL, ++ .decrypt_mpdu = NULL, ++ .encrypt_msdu = NULL, ++ .decrypt_msdu = NULL, ++ .set_key = NULL, ++ .get_key = NULL, ++ .extra_prefix_len = 0, ++ .extra_postfix_len = 0, ++ .owner = THIS_MODULE, ++}; ++ ++ ++int __init ieee80211_crypto_init(void) ++{ ++ int ret = -ENOMEM; ++ ++ hcrypt = kmalloc(sizeof(*hcrypt), GFP_KERNEL); ++ if (!hcrypt) ++ goto out; ++ ++ memset(hcrypt, 0, sizeof(*hcrypt)); ++ INIT_LIST_HEAD(&hcrypt->algs); ++ spin_lock_init(&hcrypt->lock); ++ ++ ret = ieee80211_register_crypto_ops(&ieee80211_crypt_null); ++ if (ret < 0) { ++ kfree(hcrypt); ++ hcrypt = NULL; ++ } ++out: ++ return ret; ++} ++ ++ ++void __exit ieee80211_crypto_deinit(void) ++{ ++ struct list_head *ptr, *n; ++ ++ if (hcrypt == NULL) ++ return; ++ ++ for (ptr = hcrypt->algs.next, n = ptr->next; ptr != &hcrypt->algs; ++ ptr = n, n = ptr->next) { ++ struct ieee80211_crypto_alg *alg = ++ (struct ieee80211_crypto_alg *) ptr; ++ list_del(ptr); ++ printk(KERN_DEBUG "ieee80211_crypt: unregistered algorithm " ++ "'%s' (deinit)\n", alg->ops->name); ++ kfree(alg); ++ } ++ ++ kfree(hcrypt); ++} ++ ++#if 0 ++#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0)) ++EXPORT_SYMBOL(ieee80211_crypt_deinit_entries); ++EXPORT_SYMBOL(ieee80211_crypt_deinit_handler); ++EXPORT_SYMBOL(ieee80211_crypt_delayed_deinit); ++ ++EXPORT_SYMBOL(ieee80211_register_crypto_ops); ++EXPORT_SYMBOL(ieee80211_unregister_crypto_ops); ++EXPORT_SYMBOL(ieee80211_get_crypto_ops); ++#else ++EXPORT_SYMBOL_NOVERS(ieee80211_crypt_deinit_entries); ++EXPORT_SYMBOL_NOVERS(ieee80211_crypt_deinit_handler); ++EXPORT_SYMBOL_NOVERS(ieee80211_crypt_delayed_deinit); ++ ++EXPORT_SYMBOL_NOVERS(ieee80211_register_crypto_ops); ++EXPORT_SYMBOL_NOVERS(ieee80211_unregister_crypto_ops); ++EXPORT_SYMBOL_NOVERS(ieee80211_get_crypto_ops); ++#endif ++ ++module_init(ieee80211_crypto_init); ++module_exit(ieee80211_crypto_deinit); ++#endif +diff -Nur linux-2.6.33/drivers/net/wireless/rtl8187b/ieee80211/ieee80211_crypt_ccmp.c linux-lemote/drivers/net/wireless/rtl8187b/ieee80211/ieee80211_crypt_ccmp.c +--- linux-2.6.33/drivers/net/wireless/rtl8187b/ieee80211/ieee80211_crypt_ccmp.c 1970-01-01 01:00:00.000000000 +0100 ++++ linux-lemote/drivers/net/wireless/rtl8187b/ieee80211/ieee80211_crypt_ccmp.c 2010-03-06 16:43:22.000000000 +0100 +@@ -0,0 +1,524 @@ ++/* ++ * Host AP crypt: host-based CCMP encryption implementation for Host AP driver ++ * ++ * Copyright (c) 2003-2004, Jouni Malinen <jkmaline@cc.hut.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. See README and COPYING for ++ * more details. ++ */ ++ ++//#include <linux/config.h> ++#include <linux/version.h> ++#include <linux/module.h> ++#include <linux/init.h> ++#include <linux/slab.h> ++#include <linux/random.h> ++#include <linux/skbuff.h> ++#include <linux/netdevice.h> ++#include <linux/if_ether.h> ++#include <linux/if_arp.h> ++#include <asm/string.h> ++#include <linux/wireless.h> ++ ++#include "ieee80211.h" ++ ++#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)) ++#include "rtl_crypto.h" ++#else ++#include <linux/crypto.h> ++#endif ++#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,20) ++ #include <asm/scatterlist.h> ++#else ++ #include <linux/scatterlist.h> ++#endif ++ ++//#include <asm/scatterlist.h> ++ ++MODULE_AUTHOR("Jouni Malinen"); ++MODULE_DESCRIPTION("Host AP crypt: CCMP"); ++MODULE_LICENSE("GPL"); ++ ++#define AES_BLOCK_LEN 16 ++#define CCMP_HDR_LEN 8 ++#define CCMP_MIC_LEN 8 ++#define CCMP_TK_LEN 16 ++#define CCMP_PN_LEN 6 ++ ++struct ieee80211_ccmp_data { ++ u8 key[CCMP_TK_LEN]; ++ int key_set; ++ ++ u8 tx_pn[CCMP_PN_LEN]; ++ u8 rx_pn[CCMP_PN_LEN]; ++ ++ u32 dot11RSNAStatsCCMPFormatErrors; ++ u32 dot11RSNAStatsCCMPReplays; ++ u32 dot11RSNAStatsCCMPDecryptErrors; ++ ++ int key_idx; ++ ++ struct crypto_tfm *tfm; ++ ++ /* scratch buffers for virt_to_page() (crypto API) */ ++ u8 tx_b0[AES_BLOCK_LEN], tx_b[AES_BLOCK_LEN], ++ tx_e[AES_BLOCK_LEN], tx_s0[AES_BLOCK_LEN]; ++ u8 rx_b0[AES_BLOCK_LEN], rx_b[AES_BLOCK_LEN], rx_a[AES_BLOCK_LEN]; ++}; ++ ++void ieee80211_ccmp_aes_encrypt(struct crypto_tfm *tfm, ++ const u8 pt[16], u8 ct[16]) ++{ ++ #if(LINUX_VERSION_CODE < KERNEL_VERSION(2,6,21)) ++ struct scatterlist src, dst; ++ ++ src.page = virt_to_page(pt); ++ src.offset = offset_in_page(pt); ++ src.length = AES_BLOCK_LEN; ++ ++ dst.page = virt_to_page(ct); ++ dst.offset = offset_in_page(ct); ++ dst.length = AES_BLOCK_LEN; ++ ++ crypto_cipher_encrypt(tfm, &dst, &src, AES_BLOCK_LEN); ++ #else ++ crypto_cipher_encrypt_one((void*)tfm, ct, pt); ++ #endif ++} ++ ++static void * ieee80211_ccmp_init(int key_idx) ++{ ++ struct ieee80211_ccmp_data *priv; ++ ++ priv = kmalloc(sizeof(*priv), GFP_ATOMIC); ++ if (priv == NULL) ++ goto fail; ++ memset(priv, 0, sizeof(*priv)); ++ priv->key_idx = key_idx; ++ ++ #if(LINUX_VERSION_CODE < KERNEL_VERSION(2,6,21)) ++ priv->tfm = crypto_alloc_tfm("aes", 0); ++ if (priv->tfm == NULL) { ++ printk(KERN_DEBUG "ieee80211_crypt_ccmp: could not allocate " ++ "crypto API aes\n"); ++ goto fail; ++ } ++ #else ++ priv->tfm = (void*)crypto_alloc_cipher("aes", 0, CRYPTO_ALG_ASYNC); ++ if (IS_ERR(priv->tfm)) { ++ printk(KERN_DEBUG "ieee80211_crypt_ccmp: could not allocate " ++ "crypto API aes\n"); ++ priv->tfm = NULL; ++ goto fail; ++ } ++ #endif ++ return priv; ++ ++fail: ++ if (priv) { ++ if (priv->tfm) ++ #if(LINUX_VERSION_CODE < KERNEL_VERSION(2,6,21)) ++ crypto_free_tfm(priv->tfm); ++ #else ++ crypto_free_cipher((void*)priv->tfm); ++ #endif ++ kfree(priv); ++ } ++ ++ return NULL; ++} ++ ++ ++static void ieee80211_ccmp_deinit(void *priv) ++{ ++ struct ieee80211_ccmp_data *_priv = priv; ++ if (_priv && _priv->tfm) ++ #if(LINUX_VERSION_CODE < KERNEL_VERSION(2,6,21)) ++ crypto_free_tfm(_priv->tfm); ++ #else ++ crypto_free_cipher((void*)_priv->tfm); ++ #endif ++ kfree(priv); ++} ++ ++ ++static inline void xor_block(u8 *b, u8 *a, size_t len) ++{ ++ int i; ++ for (i = 0; i < len; i++) ++ b[i] ^= a[i]; ++} ++ ++#ifndef JOHN_CCMP ++static void ccmp_init_blocks(struct crypto_tfm *tfm, ++ struct ieee80211_hdr *hdr, ++ u8 *pn, size_t dlen, u8 *b0, u8 *auth, ++ u8 *s0) ++{ ++ u8 *pos, qc = 0; ++ size_t aad_len; ++ u16 fc; ++ int a4_included, qc_included; ++ u8 aad[2 * AES_BLOCK_LEN]; ++ ++ fc = le16_to_cpu(hdr->frame_ctl); ++ a4_included = ((fc & (IEEE80211_FCTL_TODS | IEEE80211_FCTL_FROMDS)) == ++ (IEEE80211_FCTL_TODS | IEEE80211_FCTL_FROMDS)); ++ /* ++ qc_included = ((WLAN_FC_GET_TYPE(fc) == IEEE80211_FTYPE_DATA) && ++ (WLAN_FC_GET_STYPE(fc) & 0x08)); ++ */ ++ // fixed by David :2006.9.6 ++ qc_included = ((WLAN_FC_GET_TYPE(fc) == IEEE80211_FTYPE_DATA) && ++ (WLAN_FC_GET_STYPE(fc) & 0x80)); ++ aad_len = 22; ++ if (a4_included) ++ aad_len += 6; ++ if (qc_included) { ++ pos = (u8 *) &hdr->addr4; ++ if (a4_included) ++ pos += 6; ++ qc = *pos & 0x0f; ++ aad_len += 2; ++ } ++ /* CCM Initial Block: ++ * Flag (Include authentication header, M=3 (8-octet MIC), ++ * L=1 (2-octet Dlen)) ++ * Nonce: 0x00 | A2 | PN ++ * Dlen */ ++ b0[0] = 0x59; ++ b0[1] = qc; ++ memcpy(b0 + 2, hdr->addr2, ETH_ALEN); ++ memcpy(b0 + 8, pn, CCMP_PN_LEN); ++ b0[14] = (dlen >> 8) & 0xff; ++ b0[15] = dlen & 0xff; ++ ++ /* AAD: ++ * FC with bits 4..6 and 11..13 masked to zero; 14 is always one ++ * A1 | A2 | A3 ++ * SC with bits 4..15 (seq#) masked to zero ++ * A4 (if present) ++ * QC (if present) ++ */ ++ pos = (u8 *) hdr; ++ aad[0] = 0; /* aad_len >> 8 */ ++ aad[1] = aad_len & 0xff; ++ aad[2] = pos[0] & 0x8f; ++ aad[3] = pos[1] & 0xc7; ++ memcpy(aad + 4, hdr->addr1, 3 * ETH_ALEN); ++ pos = (u8 *) &hdr->seq_ctl; ++ aad[22] = pos[0] & 0x0f; ++ aad[23] = 0; /* all bits masked */ ++ memset(aad + 24, 0, 8); ++ if (a4_included) ++ memcpy(aad + 24, hdr->addr4, ETH_ALEN); ++ if (qc_included) { ++ aad[a4_included ? 30 : 24] = qc; ++ /* rest of QC masked */ ++ } ++ ++ /* Start with the first block and AAD */ ++ ieee80211_ccmp_aes_encrypt(tfm, b0, auth); ++ xor_block(auth, aad, AES_BLOCK_LEN); ++ ieee80211_ccmp_aes_encrypt(tfm, auth, auth); ++ xor_block(auth, &aad[AES_BLOCK_LEN], AES_BLOCK_LEN); ++ ieee80211_ccmp_aes_encrypt(tfm, auth, auth); ++ b0[0] &= 0x07; ++ b0[14] = b0[15] = 0; ++ ieee80211_ccmp_aes_encrypt(tfm, b0, s0); ++} ++#endif ++ ++static int ieee80211_ccmp_encrypt(struct sk_buff *skb, int hdr_len, void *priv) ++{ ++ struct ieee80211_ccmp_data *key = priv; ++ int data_len, i; ++ u8 *pos; ++ struct ieee80211_hdr *hdr; ++#ifndef JOHN_CCMP ++ int blocks, last, len; ++ u8 *mic; ++ u8 *b0 = key->tx_b0; ++ u8 *b = key->tx_b; ++ u8 *e = key->tx_e; ++ u8 *s0 = key->tx_s0; ++#endif ++ if (skb_headroom(skb) < CCMP_HDR_LEN || ++ skb_tailroom(skb) < CCMP_MIC_LEN || ++ skb->len < hdr_len) ++ return -1; ++ ++ data_len = skb->len - hdr_len; ++ pos = skb_push(skb, CCMP_HDR_LEN); ++ memmove(pos, pos + CCMP_HDR_LEN, hdr_len); ++ pos += hdr_len; ++// mic = skb_put(skb, CCMP_MIC_LEN); ++ ++ i = CCMP_PN_LEN - 1; ++ while (i >= 0) { ++ key->tx_pn[i]++; ++ if (key->tx_pn[i] != 0) ++ break; ++ i--; ++ } ++ ++ *pos++ = key->tx_pn[5]; ++ *pos++ = key->tx_pn[4]; ++ *pos++ = 0; ++ *pos++ = (key->key_idx << 6) | (1 << 5) /* Ext IV included */; ++ *pos++ = key->tx_pn[3]; ++ *pos++ = key->tx_pn[2]; ++ *pos++ = key->tx_pn[1]; ++ *pos++ = key->tx_pn[0]; ++ ++ hdr = (struct ieee80211_hdr *) skb->data; ++#ifndef JOHN_CCMP ++ //mic is moved to here by john ++ mic = skb_put(skb, CCMP_MIC_LEN); ++ ++ ccmp_init_blocks(key->tfm, hdr, key->tx_pn, data_len, b0, b, s0); ++ ++ blocks = (data_len + AES_BLOCK_LEN - 1) / AES_BLOCK_LEN; ++ last = data_len % AES_BLOCK_LEN; ++ ++ for (i = 1; i <= blocks; i++) { ++ len = (i == blocks && last) ? last : AES_BLOCK_LEN; ++ /* Authentication */ ++ xor_block(b, pos, len); ++ ieee80211_ccmp_aes_encrypt(key->tfm, b, b); ++ /* Encryption, with counter */ ++ b0[14] = (i >> 8) & 0xff; ++ b0[15] = i & 0xff; ++ ieee80211_ccmp_aes_encrypt(key->tfm, b0, e); ++ xor_block(pos, e, len); ++ pos += len; ++ } ++ ++ for (i = 0; i < CCMP_MIC_LEN; i++) ++ mic[i] = b[i] ^ s0[i]; ++#endif ++ return 0; ++} ++ ++ ++static int ieee80211_ccmp_decrypt(struct sk_buff *skb, int hdr_len, void *priv) ++{ ++ struct ieee80211_ccmp_data *key = priv; ++ u8 keyidx, *pos; ++ struct ieee80211_hdr *hdr; ++ u8 pn[6]; ++#ifndef JOHN_CCMP ++ size_t data_len = skb->len - hdr_len - CCMP_HDR_LEN - CCMP_MIC_LEN; ++ u8 *mic = skb->data + skb->len - CCMP_MIC_LEN; ++ u8 *b0 = key->rx_b0; ++ u8 *b = key->rx_b; ++ u8 *a = key->rx_a; ++ int i, blocks, last, len; ++#endif ++ if (skb->len < hdr_len + CCMP_HDR_LEN + CCMP_MIC_LEN) { ++ key->dot11RSNAStatsCCMPFormatErrors++; ++ return -1; ++ } ++ ++ hdr = (struct ieee80211_hdr *) skb->data; ++ pos = skb->data + hdr_len; ++ keyidx = pos[3]; ++ if (!(keyidx & (1 << 5))) { ++ if (net_ratelimit()) { ++ printk(KERN_DEBUG "CCMP: received packet without ExtIV" ++ " flag from " MAC_FMT "\n", MAC_ARG(hdr->addr2)); ++ } ++ key->dot11RSNAStatsCCMPFormatErrors++; ++ return -2; ++ } ++ keyidx >>= 6; ++ if (key->key_idx != keyidx) { ++ printk(KERN_DEBUG "CCMP: RX tkey->key_idx=%d frame " ++ "keyidx=%d priv=%p\n", key->key_idx, keyidx, priv); ++ return -6; ++ } ++ if (!key->key_set) { ++ if (net_ratelimit()) { ++ printk(KERN_DEBUG "CCMP: received packet from " MAC_FMT ++ " with keyid=%d that does not have a configured" ++ " key\n", MAC_ARG(hdr->addr2), keyidx); ++ } ++ return -3; ++ } ++ ++ pn[0] = pos[7]; ++ pn[1] = pos[6]; ++ pn[2] = pos[5]; ++ pn[3] = pos[4]; ++ pn[4] = pos[1]; ++ pn[5] = pos[0]; ++ pos += 8; ++#if 0 ++ if (memcmp(pn, key->rx_pn, CCMP_PN_LEN) <= 0) { ++ if (net_ratelimit()) { ++ printk(KERN_DEBUG "CCMP: replay detected: STA=" MAC_FMT ++ " previous PN %02x%02x%02x%02x%02x%02x " ++ "received PN %02x%02x%02x%02x%02x%02x\n", ++ MAC_ARG(hdr->addr2), MAC_ARG(key->rx_pn), ++ MAC_ARG(pn)); ++ } ++ key->dot11RSNAStatsCCMPReplays++; ++ return -4; ++ } ++#endif ++#ifndef JOHN_CCMP ++ ccmp_init_blocks(key->tfm, hdr, pn, data_len, b0, a, b); ++ xor_block(mic, b, CCMP_MIC_LEN); ++ ++ blocks = (data_len + AES_BLOCK_LEN - 1) / AES_BLOCK_LEN; ++ last = data_len % AES_BLOCK_LEN; ++ ++ for (i = 1; i <= blocks; i++) { ++ len = (i == blocks && last) ? last : AES_BLOCK_LEN; ++ /* Decrypt, with counter */ ++ b0[14] = (i >> 8) & 0xff; ++ b0[15] = i & 0xff; ++ ieee80211_ccmp_aes_encrypt(key->tfm, b0, b); ++ xor_block(pos, b, len); ++ /* Authentication */ ++ xor_block(a, pos, len); ++ ieee80211_ccmp_aes_encrypt(key->tfm, a, a); ++ pos += len; ++ } ++ ++ if (memcmp(mic, a, CCMP_MIC_LEN) != 0) { ++ if (net_ratelimit()) { ++ printk(KERN_DEBUG "CCMP: decrypt failed: STA=" ++ MAC_FMT "\n", MAC_ARG(hdr->addr2)); ++ } ++ key->dot11RSNAStatsCCMPDecryptErrors++; ++ return -5; ++ } ++ ++ memcpy(key->rx_pn, pn, CCMP_PN_LEN); ++ ++#endif ++ /* Remove hdr and MIC */ ++ memmove(skb->data + CCMP_HDR_LEN, skb->data, hdr_len); ++ skb_pull(skb, CCMP_HDR_LEN); ++ skb_trim(skb, skb->len - CCMP_MIC_LEN); ++ ++ return keyidx; ++} ++ ++ ++static int ieee80211_ccmp_set_key(void *key, int len, u8 *seq, void *priv) ++{ ++ struct ieee80211_ccmp_data *data = priv; ++ int keyidx; ++ struct crypto_tfm *tfm = data->tfm; ++ ++ keyidx = data->key_idx; ++ memset(data, 0, sizeof(*data)); ++ data->key_idx = keyidx; ++ data->tfm = tfm; ++ if (len == CCMP_TK_LEN) { ++ memcpy(data->key, key, CCMP_TK_LEN); ++ data->key_set = 1; ++ if (seq) { ++ data->rx_pn[0] = seq[5]; ++ data->rx_pn[1] = seq[4]; ++ data->rx_pn[2] = seq[3]; ++ data->rx_pn[3] = seq[2]; ++ data->rx_pn[4] = seq[1]; ++ data->rx_pn[5] = seq[0]; ++ } ++ crypto_cipher_setkey((void*)data->tfm, data->key, CCMP_TK_LEN); ++ } else if (len == 0) ++ data->key_set = 0; ++ else ++ return -1; ++ ++ return 0; ++} ++ ++ ++static int ieee80211_ccmp_get_key(void *key, int len, u8 *seq, void *priv) ++{ ++ struct ieee80211_ccmp_data *data = priv; ++ ++ if (len < CCMP_TK_LEN) ++ return -1; ++ ++ if (!data->key_set) ++ return 0; ++ memcpy(key, data->key, CCMP_TK_LEN); ++ ++ if (seq) { ++ seq[0] = data->tx_pn[5]; ++ seq[1] = data->tx_pn[4]; ++ seq[2] = data->tx_pn[3]; ++ seq[3] = data->tx_pn[2]; ++ seq[4] = data->tx_pn[1]; ++ seq[5] = data->tx_pn[0]; ++ } ++ ++ return CCMP_TK_LEN; ++} ++ ++ ++static char * ieee80211_ccmp_print_stats(char *p, void *priv) ++{ ++ struct ieee80211_ccmp_data *ccmp = priv; ++ p += sprintf(p, "key[%d] alg=CCMP key_set=%d " ++ "tx_pn=%02x%02x%02x%02x%02x%02x " ++ "rx_pn=%02x%02x%02x%02x%02x%02x " ++ "format_errors=%d replays=%d decrypt_errors=%d\n", ++ ccmp->key_idx, ccmp->key_set, ++ MAC_ARG(ccmp->tx_pn), MAC_ARG(ccmp->rx_pn), ++ ccmp->dot11RSNAStatsCCMPFormatErrors, ++ ccmp->dot11RSNAStatsCCMPReplays, ++ ccmp->dot11RSNAStatsCCMPDecryptErrors); ++ ++ return p; ++} ++ ++void ieee80211_ccmp_null(void) ++{ ++ // printk("============>%s()\n", __FUNCTION__); ++ return; ++} ++static struct ieee80211_crypto_ops ieee80211_crypt_ccmp = { ++ .name = "CCMP", ++ .init = ieee80211_ccmp_init, ++ .deinit = ieee80211_ccmp_deinit, ++ .encrypt_mpdu = ieee80211_ccmp_encrypt, ++ .decrypt_mpdu = ieee80211_ccmp_decrypt, ++ .encrypt_msdu = NULL, ++ .decrypt_msdu = NULL, ++ .set_key = ieee80211_ccmp_set_key, ++ .get_key = ieee80211_ccmp_get_key, ++ .print_stats = ieee80211_ccmp_print_stats, ++ .extra_prefix_len = CCMP_HDR_LEN, ++ .extra_postfix_len = CCMP_MIC_LEN, ++ .owner = THIS_MODULE, ++}; ++ ++ ++int __init ieee80211_crypto_ccmp_init(void) ++{ ++ return ieee80211_register_crypto_ops(&ieee80211_crypt_ccmp); ++} ++ ++ ++void __exit ieee80211_crypto_ccmp_exit(void) ++{ ++ ieee80211_unregister_crypto_ops(&ieee80211_crypt_ccmp); ++} ++#if 0 ++#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0)) ++EXPORT_SYMBOL(ieee80211_ccmp_null); ++#else ++EXPORT_SYMBOL_NOVERS(ieee80211_ccmp_null); ++#endif ++ ++module_init(ieee80211_crypto_ccmp_init); ++module_exit(ieee80211_crypto_ccmp_exit); ++#endif +diff -Nur linux-2.6.33/drivers/net/wireless/rtl8187b/ieee80211/ieee80211_crypt.h linux-lemote/drivers/net/wireless/rtl8187b/ieee80211/ieee80211_crypt.h +--- linux-2.6.33/drivers/net/wireless/rtl8187b/ieee80211/ieee80211_crypt.h 1970-01-01 01:00:00.000000000 +0100 ++++ linux-lemote/drivers/net/wireless/rtl8187b/ieee80211/ieee80211_crypt.h 2010-03-06 16:43:22.000000000 +0100 +@@ -0,0 +1,91 @@ ++/* ++ * Original code based on Host AP (software wireless LAN access point) driver ++ * for Intersil Prism2/2.5/3. ++ * ++ * Copyright (c) 2001-2002, SSH Communications Security Corp and Jouni Malinen ++ * <jkmaline@cc.hut.fi> ++ * Copyright (c) 2002-2003, Jouni Malinen <jkmaline@cc.hut.fi> ++ * ++ * Adaption to a generic IEEE 802.11 stack by James Ketrenos ++ * <jketreno@linux.intel.com> ++ * ++ * Copyright (c) 2004, Intel Corporation ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License version 2 as ++ * published by the Free Software Foundation. See README and COPYING for ++ * more details. ++ */ ++ ++/* ++ * This file defines the interface to the ieee80211 crypto module. ++ */ ++#ifndef IEEE80211_CRYPT_H ++#define IEEE80211_CRYPT_H ++ ++#include <linux/skbuff.h> ++ ++struct ieee80211_crypto_ops { ++ const char *name; ++ ++ /* init new crypto context (e.g., allocate private data space, ++ * select IV, etc.); returns NULL on failure or pointer to allocated ++ * private data on success */ ++ void * (*init)(int keyidx); ++ ++ /* deinitialize crypto context and free allocated private data */ ++ void (*deinit)(void *priv); ++ ++ /* encrypt/decrypt return < 0 on error or >= 0 on success. The return ++ * value from decrypt_mpdu is passed as the keyidx value for ++ * decrypt_msdu. skb must have enough head and tail room for the ++ * encryption; if not, error will be returned; these functions are ++ * called for all MPDUs (i.e., fragments). ++ */ ++ int (*encrypt_mpdu)(struct sk_buff *skb, int hdr_len, void *priv); ++ int (*decrypt_mpdu)(struct sk_buff *skb, int hdr_len, void *priv); ++ ++ /* These functions are called for full MSDUs, i.e. full frames. ++ * These can be NULL if full MSDU operations are not needed. */ ++ int (*encrypt_msdu)(struct sk_buff *skb, int hdr_len, void *priv); ++ int (*decrypt_msdu)(struct sk_buff *skb, int keyidx, int hdr_len, ++ void *priv); ++ ++ int (*set_key)(void *key, int len, u8 *seq, void *priv); ++ int (*get_key)(void *key, int len, u8 *seq, void *priv); ++ ++ /* procfs handler for printing out key information and possible ++ * statistics */ ++ char * (*print_stats)(char *p, void *priv); ++ ++ /* maximum number of bytes added by encryption; encrypt buf is ++ * allocated with extra_prefix_len bytes, copy of in_buf, and ++ * extra_postfix_len; encrypt need not use all this space, but ++ * the result must start at the beginning of the buffer and correct ++ * length must be returned */ ++ int extra_prefix_len, extra_postfix_len; ++ ++ struct module *owner; ++}; ++ ++struct ieee80211_crypt_data { ++ struct list_head list; /* delayed deletion list */ ++ struct ieee80211_crypto_ops *ops; ++ void *priv; ++ atomic_t refcnt; ++}; ++ ++int ieee80211_register_crypto_ops(struct ieee80211_crypto_ops *ops); ++int ieee80211_unregister_crypto_ops(struct ieee80211_crypto_ops *ops); ++struct ieee80211_crypto_ops * ieee80211_get_crypto_ops(const char *name); ++void ieee80211_crypt_deinit_entries(struct ieee80211_device *, int); ++void ieee80211_crypt_deinit_handler(unsigned long); ++void ieee80211_crypt_delayed_deinit(struct ieee80211_device *ieee, ++ struct ieee80211_crypt_data **crypt); ++#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)) ++#define offset_in_page(p) ((unsigned long)(p) & ~PAGE_MASK) ++#define crypto_alloc_tfm crypto_alloc_tfm_rtl ++#define crypto_free_tfm crypto_free_tfm_rtl ++#endif ++ ++#endif +diff -Nur linux-2.6.33/drivers/net/wireless/rtl8187b/ieee80211/ieee80211_crypt_tkip.c linux-lemote/drivers/net/wireless/rtl8187b/ieee80211/ieee80211_crypt_tkip.c +--- linux-2.6.33/drivers/net/wireless/rtl8187b/ieee80211/ieee80211_crypt_tkip.c 1970-01-01 01:00:00.000000000 +0100 ++++ linux-lemote/drivers/net/wireless/rtl8187b/ieee80211/ieee80211_crypt_tkip.c 2010-03-06 16:43:22.000000000 +0100 +@@ -0,0 +1,996 @@ ++/* ++ * Host AP crypt: host-based TKIP encryption implementation for Host AP driver ++ * ++ * Copyright (c) 2003-2004, Jouni Malinen <jkmaline@cc.hut.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. See README and COPYING for ++ * more details. ++ */ ++ ++//#include <linux/config.h> ++#include <linux/version.h> ++#include <linux/module.h> ++#include <linux/init.h> ++#include <linux/slab.h> ++#include <linux/random.h> ++#include <linux/skbuff.h> ++#include <linux/netdevice.h> ++#include <linux/if_ether.h> ++#include <linux/if_arp.h> ++#include <asm/string.h> ++ ++#include "ieee80211.h" ++ ++#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)) ++#include "rtl_crypto.h" ++#else ++#include <linux/crypto.h> ++#endif ++//#include <asm/scatterlist.h> ++#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,20) ++ #include <asm/scatterlist.h> ++#else ++ #include <linux/scatterlist.h> ++#endif ++ ++#include <linux/crc32.h> ++ ++MODULE_AUTHOR("Jouni Malinen"); ++MODULE_DESCRIPTION("Host AP crypt: TKIP"); ++MODULE_LICENSE("GPL"); ++ ++struct ieee80211_tkip_data { ++#define TKIP_KEY_LEN 32 ++ u8 key[TKIP_KEY_LEN]; ++ int key_set; ++ ++ u32 tx_iv32; ++ u16 tx_iv16; ++ u16 tx_ttak[5]; ++ int tx_phase1_done; ++ ++ u32 rx_iv32; ++ u16 rx_iv16; ++ u16 rx_ttak[5]; ++ int rx_phase1_done; ++ u32 rx_iv32_new; ++ u16 rx_iv16_new; ++ ++ u32 dot11RSNAStatsTKIPReplays; ++ u32 dot11RSNAStatsTKIPICVErrors; ++ u32 dot11RSNAStatsTKIPLocalMICFailures; ++ ++ int key_idx; ++ ++ #if(LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,21)) ++ struct crypto_blkcipher *rx_tfm_arc4; ++ struct crypto_hash *rx_tfm_michael; ++ struct crypto_blkcipher *tx_tfm_arc4; ++ struct crypto_hash *tx_tfm_michael; ++ #endif ++ ++ struct crypto_tfm *tfm_arc4; ++ struct crypto_tfm *tfm_michael; ++ ++ /* scratch buffers for virt_to_page() (crypto API) */ ++ u8 rx_hdr[16], tx_hdr[16]; ++}; ++ ++static void * ieee80211_tkip_init(int key_idx) ++{ ++ struct ieee80211_tkip_data *priv; ++ ++ priv = kmalloc(sizeof(*priv), GFP_ATOMIC); ++ if (priv == NULL) ++ goto fail; ++ memset(priv, 0, sizeof(*priv)); ++ priv->key_idx = key_idx; ++ ++ #if(LINUX_VERSION_CODE < KERNEL_VERSION(2,6,21)) ++ priv->tfm_arc4 = crypto_alloc_tfm("arc4", 0); ++ if (priv->tfm_arc4 == NULL) { ++ printk(KERN_DEBUG "ieee80211_crypt_tkip: could not allocate " ++ "crypto API arc4\n"); ++ goto fail; ++ } ++ ++ priv->tfm_michael = crypto_alloc_tfm("michael_mic", 0); ++ if (priv->tfm_michael == NULL) { ++ printk(KERN_DEBUG "ieee80211_crypt_tkip: could not allocate " ++ "crypto API michael_mic\n"); ++ goto fail; ++ } ++ ++ #else ++ priv->tx_tfm_arc4 = crypto_alloc_blkcipher("ecb(arc4)", 0, ++ CRYPTO_ALG_ASYNC); ++ if (IS_ERR(priv->tx_tfm_arc4)) { ++ printk(KERN_DEBUG "ieee80211_crypt_tkip: could not allocate " ++ "crypto API arc4\n"); ++ priv->tx_tfm_arc4 = NULL; ++ goto fail; ++ } ++ ++ priv->tx_tfm_michael = crypto_alloc_hash("michael_mic", 0, ++ CRYPTO_ALG_ASYNC); ++ if (IS_ERR(priv->tx_tfm_michael)) { ++ printk(KERN_DEBUG "ieee80211_crypt_tkip: could not allocate " ++ "crypto API michael_mic\n"); ++ priv->tx_tfm_michael = NULL; ++ goto fail; ++ } ++ ++ priv->rx_tfm_arc4 = crypto_alloc_blkcipher("ecb(arc4)", 0, ++ CRYPTO_ALG_ASYNC); ++ if (IS_ERR(priv->rx_tfm_arc4)) { ++ printk(KERN_DEBUG "ieee80211_crypt_tkip: could not allocate " ++ "crypto API arc4\n"); ++ priv->rx_tfm_arc4 = NULL; ++ goto fail; ++ } ++ ++ priv->rx_tfm_michael = crypto_alloc_hash("michael_mic", 0, ++ CRYPTO_ALG_ASYNC); ++ if (IS_ERR(priv->rx_tfm_michael)) { ++ printk(KERN_DEBUG "ieee80211_crypt_tkip: could not allocate " ++ "crypto API michael_mic\n"); ++ priv->rx_tfm_michael = NULL; ++ goto fail; ++ } ++ #endif ++ return priv; ++ ++fail: ++ if (priv) { ++ #if(LINUX_VERSION_CODE < KERNEL_VERSION(2,6,21)) ++ if (priv->tfm_michael) ++ crypto_free_tfm(priv->tfm_michael); ++ if (priv->tfm_arc4) ++ crypto_free_tfm(priv->tfm_arc4); ++ #else ++ if (priv->tx_tfm_michael) ++ crypto_free_hash(priv->tx_tfm_michael); ++ if (priv->tx_tfm_arc4) ++ crypto_free_blkcipher(priv->tx_tfm_arc4); ++ if (priv->rx_tfm_michael) ++ crypto_free_hash(priv->rx_tfm_michael); ++ if (priv->rx_tfm_arc4) ++ crypto_free_blkcipher(priv->rx_tfm_arc4); ++ #endif ++ kfree(priv); ++ } ++ ++ return NULL; ++} ++ ++ ++static void ieee80211_tkip_deinit(void *priv) ++{ ++ struct ieee80211_tkip_data *_priv = priv; ++ #if(LINUX_VERSION_CODE < KERNEL_VERSION(2,6,21)) ++ if (_priv && _priv->tfm_michael) ++ crypto_free_tfm(_priv->tfm_michael); ++ if (_priv && _priv->tfm_arc4) ++ crypto_free_tfm(_priv->tfm_arc4); ++ #else ++ if (_priv) { ++ if (_priv->tx_tfm_michael) ++ crypto_free_hash(_priv->tx_tfm_michael); ++ if (_priv->tx_tfm_arc4) ++ crypto_free_blkcipher(_priv->tx_tfm_arc4); ++ if (_priv->rx_tfm_michael) ++ crypto_free_hash(_priv->rx_tfm_michael); ++ if (_priv->rx_tfm_arc4) ++ crypto_free_blkcipher(_priv->rx_tfm_arc4); ++ } ++ #endif ++ kfree(priv); ++} ++ ++ ++static inline u16 RotR1(u16 val) ++{ ++ return (val >> 1) | (val << 15); ++} ++ ++ ++static inline u8 Lo8(u16 val) ++{ ++ return val & 0xff; ++} ++ ++ ++static inline u8 Hi8(u16 val) ++{ ++ return val >> 8; ++} ++ ++ ++static inline u16 Lo16(u32 val) ++{ ++ return val & 0xffff; ++} ++ ++ ++static inline u16 Hi16(u32 val) ++{ ++ return val >> 16; ++} ++ ++ ++static inline u16 Mk16(u8 hi, u8 lo) ++{ ++ return lo | (((u16) hi) << 8); ++} ++ ++ ++static inline u16 Mk16_le(u16 *v) ++{ ++ return le16_to_cpu(*v); ++} ++ ++ ++static const u16 Sbox[256] = ++{ ++ 0xC6A5, 0xF884, 0xEE99, 0xF68D, 0xFF0D, 0xD6BD, 0xDEB1, 0x9154, ++ 0x6050, 0x0203, 0xCEA9, 0x567D, 0xE719, 0xB562, 0x4DE6, 0xEC9A, ++ 0x8F45, 0x1F9D, 0x8940, 0xFA87, 0xEF15, 0xB2EB, 0x8EC9, 0xFB0B, ++ 0x41EC, 0xB367, 0x5FFD, 0x45EA, 0x23BF, 0x53F7, 0xE496, 0x9B5B, ++ 0x75C2, 0xE11C, 0x3DAE, 0x4C6A, 0x6C5A, 0x7E41, 0xF502, 0x834F, ++ 0x685C, 0x51F4, 0xD134, 0xF908, 0xE293, 0xAB73, 0x6253, 0x2A3F, ++ 0x080C, 0x9552, 0x4665, 0x9D5E, 0x3028, 0x37A1, 0x0A0F, 0x2FB5, ++ 0x0E09, 0x2436, 0x1B9B, 0xDF3D, 0xCD26, 0x4E69, 0x7FCD, 0xEA9F, ++ 0x121B, 0x1D9E, 0x5874, 0x342E, 0x362D, 0xDCB2, 0xB4EE, 0x5BFB, ++ 0xA4F6, 0x764D, 0xB761, 0x7DCE, 0x527B, 0xDD3E, 0x5E71, 0x1397, ++ 0xA6F5, 0xB968, 0x0000, 0xC12C, 0x4060, 0xE31F, 0x79C8, 0xB6ED, ++ 0xD4BE, 0x8D46, 0x67D9, 0x724B, 0x94DE, 0x98D4, 0xB0E8, 0x854A, ++ 0xBB6B, 0xC52A, 0x4FE5, 0xED16, 0x86C5, 0x9AD7, 0x6655, 0x1194, ++ 0x8ACF, 0xE910, 0x0406, 0xFE81, 0xA0F0, 0x7844, 0x25BA, 0x4BE3, ++ 0xA2F3, 0x5DFE, 0x80C0, 0x058A, 0x3FAD, 0x21BC, 0x7048, 0xF104, ++ 0x63DF, 0x77C1, 0xAF75, 0x4263, 0x2030, 0xE51A, 0xFD0E, 0xBF6D, ++ 0x814C, 0x1814, 0x2635, 0xC32F, 0xBEE1, 0x35A2, 0x88CC, 0x2E39, ++ 0x9357, 0x55F2, 0xFC82, 0x7A47, 0xC8AC, 0xBAE7, 0x322B, 0xE695, ++ 0xC0A0, 0x1998, 0x9ED1, 0xA37F, 0x4466, 0x547E, 0x3BAB, 0x0B83, ++ 0x8CCA, 0xC729, 0x6BD3, 0x283C, 0xA779, 0xBCE2, 0x161D, 0xAD76, ++ 0xDB3B, 0x6456, 0x744E, 0x141E, 0x92DB, 0x0C0A, 0x486C, 0xB8E4, ++ 0x9F5D, 0xBD6E, 0x43EF, 0xC4A6, 0x39A8, 0x31A4, 0xD337, 0xF28B, ++ 0xD532, 0x8B43, 0x6E59, 0xDAB7, 0x018C, 0xB164, 0x9CD2, 0x49E0, ++ 0xD8B4, 0xACFA, 0xF307, 0xCF25, 0xCAAF, 0xF48E, 0x47E9, 0x1018, ++ 0x6FD5, 0xF088, 0x4A6F, 0x5C72, 0x3824, 0x57F1, 0x73C7, 0x9751, ++ 0xCB23, 0xA17C, 0xE89C, 0x3E21, 0x96DD, 0x61DC, 0x0D86, 0x0F85, ++ 0xE090, 0x7C42, 0x71C4, 0xCCAA, 0x90D8, 0x0605, 0xF701, 0x1C12, ++ 0xC2A3, 0x6A5F, 0xAEF9, 0x69D0, 0x1791, 0x9958, 0x3A27, 0x27B9, ++ 0xD938, 0xEB13, 0x2BB3, 0x2233, 0xD2BB, 0xA970, 0x0789, 0x33A7, ++ 0x2DB6, 0x3C22, 0x1592, 0xC920, 0x8749, 0xAAFF, 0x5078, 0xA57A, ++ 0x038F, 0x59F8, 0x0980, 0x1A17, 0x65DA, 0xD731, 0x84C6, 0xD0B8, ++ 0x82C3, 0x29B0, 0x5A77, 0x1E11, 0x7BCB, 0xA8FC, 0x6DD6, 0x2C3A, ++}; ++ ++ ++static inline u16 _S_(u16 v) ++{ ++ u16 t = Sbox[Hi8(v)]; ++ return Sbox[Lo8(v)] ^ ((t << 8) | (t >> 8)); ++} ++ ++#ifndef JOHN_TKIP ++#define PHASE1_LOOP_COUNT 8 ++ ++static void tkip_mixing_phase1(u16 *TTAK, const u8 *TK, const u8 *TA, u32 IV32) ++{ ++ int i, j; ++ ++ /* Initialize the 80-bit TTAK from TSC (IV32) and TA[0..5] */ ++ TTAK[0] = Lo16(IV32); ++ TTAK[1] = Hi16(IV32); ++ TTAK[2] = Mk16(TA[1], TA[0]); ++ TTAK[3] = Mk16(TA[3], TA[2]); ++ TTAK[4] = Mk16(TA[5], TA[4]); ++ ++ for (i = 0; i < PHASE1_LOOP_COUNT; i++) { ++ j = 2 * (i & 1); ++ TTAK[0] += _S_(TTAK[4] ^ Mk16(TK[1 + j], TK[0 + j])); ++ TTAK[1] += _S_(TTAK[0] ^ Mk16(TK[5 + j], TK[4 + j])); ++ TTAK[2] += _S_(TTAK[1] ^ Mk16(TK[9 + j], TK[8 + j])); ++ TTAK[3] += _S_(TTAK[2] ^ Mk16(TK[13 + j], TK[12 + j])); ++ TTAK[4] += _S_(TTAK[3] ^ Mk16(TK[1 + j], TK[0 + j])) + i; ++ } ++} ++ ++ ++static void tkip_mixing_phase2(u8 *WEPSeed, const u8 *TK, const u16 *TTAK, ++ u16 IV16) ++{ ++ /* Make temporary area overlap WEP seed so that the final copy can be ++ * avoided on little endian hosts. */ ++ u16 *PPK = (u16 *) &WEPSeed[4]; ++ ++ /* Step 1 - make copy of TTAK and bring in TSC */ ++ PPK[0] = TTAK[0]; ++ PPK[1] = TTAK[1]; ++ PPK[2] = TTAK[2]; ++ PPK[3] = TTAK[3]; ++ PPK[4] = TTAK[4]; ++ PPK[5] = TTAK[4] + IV16; ++ ++ /* Step 2 - 96-bit bijective mixing using S-box */ ++ PPK[0] += _S_(PPK[5] ^ Mk16_le((u16 *) &TK[0])); ++ PPK[1] += _S_(PPK[0] ^ Mk16_le((u16 *) &TK[2])); ++ PPK[2] += _S_(PPK[1] ^ Mk16_le((u16 *) &TK[4])); ++ PPK[3] += _S_(PPK[2] ^ Mk16_le((u16 *) &TK[6])); ++ PPK[4] += _S_(PPK[3] ^ Mk16_le((u16 *) &TK[8])); ++ PPK[5] += _S_(PPK[4] ^ Mk16_le((u16 *) &TK[10])); ++ ++ PPK[0] += RotR1(PPK[5] ^ Mk16_le((u16 *) &TK[12])); ++ PPK[1] += RotR1(PPK[0] ^ Mk16_le((u16 *) &TK[14])); ++ PPK[2] += RotR1(PPK[1]); ++ PPK[3] += RotR1(PPK[2]); ++ PPK[4] += RotR1(PPK[3]); ++ PPK[5] += RotR1(PPK[4]); ++ ++ /* Step 3 - bring in last of TK bits, assign 24-bit WEP IV value ++ * WEPSeed[0..2] is transmitted as WEP IV */ ++ WEPSeed[0] = Hi8(IV16); ++ WEPSeed[1] = (Hi8(IV16) | 0x20) & 0x7F; ++ WEPSeed[2] = Lo8(IV16); ++ WEPSeed[3] = Lo8((PPK[5] ^ Mk16_le((u16 *) &TK[0])) >> 1); ++ ++#ifdef __BIG_ENDIAN ++ { ++ int i; ++ for (i = 0; i < 6; i++) ++ PPK[i] = (PPK[i] << 8) | (PPK[i] >> 8); ++ } ++#endif ++} ++#endif ++static int ieee80211_tkip_encrypt(struct sk_buff *skb, int hdr_len, void *priv) ++{ ++ struct ieee80211_tkip_data *tkey = priv; ++ #if(LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,21)) ++ struct blkcipher_desc desc = {.tfm = tkey->tx_tfm_arc4}; ++ #endif ++ int len; ++ u8 *pos; ++ struct ieee80211_hdr *hdr; ++#ifndef JOHN_TKIP ++ u8 rc4key[16],*icv; ++ u32 crc; ++ struct scatterlist sg; ++#endif ++ #if(LINUX_VERSION_CODE >=KERNEL_VERSION(2,6,21)) ++ int ret; ++ #endif ++ ++ if (skb_headroom(skb) < 8 || skb_tailroom(skb) < 4 || ++ skb->len < hdr_len) ++ return -1; ++ ++ hdr = (struct ieee80211_hdr *) skb->data; ++#if 0 ++printk("@@ tkey\n"); ++printk("%x|", ((u32*)tkey->key)[0]); ++printk("%x|", ((u32*)tkey->key)[1]); ++printk("%x|", ((u32*)tkey->key)[2]); ++printk("%x|", ((u32*)tkey->key)[3]); ++printk("%x|", ((u32*)tkey->key)[4]); ++printk("%x|", ((u32*)tkey->key)[5]); ++printk("%x|", ((u32*)tkey->key)[6]); ++printk("%x\n", ((u32*)tkey->key)[7]); ++#endif ++ ++#ifndef JOHN_TKIP ++ if (!tkey->tx_phase1_done) { ++ tkip_mixing_phase1(tkey->tx_ttak, tkey->key, hdr->addr2, ++ tkey->tx_iv32); ++ tkey->tx_phase1_done = 1; ++ } ++ tkip_mixing_phase2(rc4key, tkey->key, tkey->tx_ttak, tkey->tx_iv16); ++ ++#else ++ tkey->tx_phase1_done = 1; ++#endif /*JOHN_TKIP*/ ++ ++ len = skb->len - hdr_len; ++ pos = skb_push(skb, 8); ++ memmove(pos, pos + 8, hdr_len); ++ pos += hdr_len; ++ ++#ifdef JOHN_TKIP ++ *pos++ = Hi8(tkey->tx_iv16); ++ *pos++ = (Hi8(tkey->tx_iv16) | 0x20) & 0x7F; ++ *pos++ = Lo8(tkey->tx_iv16); ++#else ++ *pos++ = rc4key[0]; ++ *pos++ = rc4key[1]; ++ *pos++ = rc4key[2]; ++#endif ++ *pos++ = (tkey->key_idx << 6) | (1 << 5) /* Ext IV included */; ++ *pos++ = tkey->tx_iv32 & 0xff; ++ *pos++ = (tkey->tx_iv32 >> 8) & 0xff; ++ *pos++ = (tkey->tx_iv32 >> 16) & 0xff; ++ *pos++ = (tkey->tx_iv32 >> 24) & 0xff; ++#ifndef JOHN_TKIP ++ icv = skb_put(skb, 4); ++#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0)) ++ crc = ~crc32_le(~0, pos, len); ++#else ++ crc = ~ether_crc_le(len, pos); ++#endif ++ icv[0] = crc; ++ icv[1] = crc >> 8; ++ icv[2] = crc >> 16; ++ icv[3] = crc >> 24; ++ #if(LINUX_VERSION_CODE < KERNEL_VERSION(2,6,21)) ++ crypto_cipher_setkey(tkey->tfm_arc4, rc4key, 16); ++ sg.page = virt_to_page(pos); ++ sg.offset = offset_in_page(pos); ++ sg.length = len + 4; ++ crypto_cipher_encrypt(tkey->tfm_arc4, &sg, &sg, len + 4); ++ #else ++ crypto_blkcipher_setkey(tkey->tx_tfm_arc4, rc4key, 16); ++ #if(LINUX_VERSION_CODE < KERNEL_VERSION(2,6,24)) ++ sg.page = virt_to_page(pos); ++ sg.offset = offset_in_page(pos); ++ sg.length = len + 4; ++ #else ++ sg_init_one(&sg, pos, len + 4); ++ #endif ++ ret= crypto_blkcipher_encrypt(&desc, &sg, &sg, len + 4); ++ #endif ++#endif ++ tkey->tx_iv16++; ++ if (tkey->tx_iv16 == 0) { ++ tkey->tx_phase1_done = 0; ++ tkey->tx_iv32++; ++ } ++#ifndef JOHN_TKIP ++ #if(LINUX_VERSION_CODE <KERNEL_VERSION(2,6,21)) ++ return 0; ++ #else ++ return ret; ++ #endif ++#else ++ return 0; ++#endif ++} ++ ++static int ieee80211_tkip_decrypt(struct sk_buff *skb, int hdr_len, void *priv) ++{ ++ struct ieee80211_tkip_data *tkey = priv; ++ #if(LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,21)) ++ struct blkcipher_desc desc = {.tfm = tkey->rx_tfm_arc4}; ++ #endif ++ u8 keyidx, *pos; ++ u32 iv32; ++ u16 iv16; ++ struct ieee80211_hdr *hdr; ++#ifndef JOHN_TKIP ++ u8 icv[4]; ++ u32 crc; ++ struct scatterlist sg; ++ u8 rc4key[16]; ++ int plen; ++#endif ++ if (skb->len < hdr_len + 8 + 4) ++ return -1; ++ ++ hdr = (struct ieee80211_hdr *) skb->data; ++ pos = skb->data + hdr_len; ++ keyidx = pos[3]; ++ if (!(keyidx & (1 << 5))) { ++ if (net_ratelimit()) { ++ printk(KERN_DEBUG "TKIP: received packet without ExtIV" ++ " flag from " MAC_FMT "\n", MAC_ARG(hdr->addr2)); ++ } ++ return -2; ++ } ++ keyidx >>= 6; ++ if (tkey->key_idx != keyidx) { ++ printk(KERN_DEBUG "TKIP: RX tkey->key_idx=%d frame " ++ "keyidx=%d priv=%p\n", tkey->key_idx, keyidx, priv); ++ return -6; ++ } ++ if (!tkey->key_set) { ++ if (net_ratelimit()) { ++ printk(KERN_DEBUG "TKIP: received packet from " MAC_FMT ++ " with keyid=%d that does not have a configured" ++ " key\n", MAC_ARG(hdr->addr2), keyidx); ++ } ++ return -3; ++ } ++ iv16 = (pos[0] << 8) | pos[2]; ++ iv32 = pos[4] | (pos[5] << 8) | (pos[6] << 16) | (pos[7] << 24); ++ pos += 8; ++#ifndef JOHN_TKIP ++#if 0 ++ if (iv32 < tkey->rx_iv32 || ++ (iv32 == tkey->rx_iv32 && iv16 <= tkey->rx_iv16)) { ++ if (net_ratelimit()) { ++ printk(KERN_DEBUG "TKIP: replay detected: STA=" MAC_FMT ++ " previous TSC %08x%04x received TSC " ++ "%08x%04x\n", MAC_ARG(hdr->addr2), ++ tkey->rx_iv32, tkey->rx_iv16, iv32, iv16); ++ } ++ tkey->dot11RSNAStatsTKIPReplays++; ++ return -4; ++ } ++#endif ++ if (iv32 != tkey->rx_iv32 || !tkey->rx_phase1_done) { ++ tkip_mixing_phase1(tkey->rx_ttak, tkey->key, hdr->addr2, iv32); ++ tkey->rx_phase1_done = 1; ++ } ++ tkip_mixing_phase2(rc4key, tkey->key, tkey->rx_ttak, iv16); ++ ++ plen = skb->len - hdr_len - 12; ++ #if(LINUX_VERSION_CODE <KERNEL_VERSION(2,6,21)) ++ crypto_cipher_setkey(tkey->tfm_arc4, rc4key, 16); ++ sg.page = virt_to_page(pos); ++ sg.offset = offset_in_page(pos); ++ sg.length = plen + 4; ++ crypto_cipher_decrypt(tkey->tfm_arc4, &sg, &sg, plen + 4); ++ #else ++ crypto_blkcipher_setkey(tkey->rx_tfm_arc4, rc4key, 16); ++ #if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 24)) ++ sg.page = virt_to_page(pos); ++ sg.offset = offset_in_page(pos); ++ sg.length = plen + 4; ++ #else ++ sg_init_one(&sg, pos, plen + 4); ++ #endif ++ if (crypto_blkcipher_decrypt(&desc, &sg, &sg, plen + 4)) { ++ if (net_ratelimit()) { ++ printk(KERN_DEBUG ": TKIP: failed to decrypt " ++ "received packet from " MAC_FMT "\n", ++ MAC_ARG(hdr->addr2)); ++ } ++ return -7; ++ } ++ #endif ++ ++#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0)) ++ crc = ~crc32_le(~0, pos, plen); ++#else ++ crc = ~ether_crc_le(plen, pos); ++#endif ++ icv[0] = crc; ++ icv[1] = crc >> 8; ++ icv[2] = crc >> 16; ++ icv[3] = crc >> 24; ++ if (memcmp(icv, pos + plen, 4) != 0) { ++ if (iv32 != tkey->rx_iv32) { ++ /* Previously cached Phase1 result was already lost, so ++ * it needs to be recalculated for the next packet. */ ++ tkey->rx_phase1_done = 0; ++ } ++ if (net_ratelimit()) { ++ printk(KERN_DEBUG "TKIP: ICV error detected: STA=" ++ MAC_FMT "\n", MAC_ARG(hdr->addr2)); ++ } ++ tkey->dot11RSNAStatsTKIPICVErrors++; ++ return -5; ++ } ++ ++#endif /* JOHN_TKIP */ ++ ++ /* Update real counters only after Michael MIC verification has ++ * completed */ ++ tkey->rx_iv32_new = iv32; ++ tkey->rx_iv16_new = iv16; ++ ++ /* Remove IV and ICV */ ++ memmove(skb->data + 8, skb->data, hdr_len); ++ skb_pull(skb, 8); ++ skb_trim(skb, skb->len - 4); ++ ++//john's test ++#ifdef JOHN_DUMP ++if( ((u16*)skb->data)[0] & 0x4000){ ++ printk("@@ rx decrypted skb->data"); ++ int i; ++ for(i=0;i<skb->len;i++){ ++ if( (i%24)==0 ) printk("\n"); ++ printk("%2x ", ((u8*)skb->data)[i]); ++ } ++ printk("\n"); ++} ++#endif /*JOHN_DUMP*/ ++ return keyidx; ++} ++ ++#if(LINUX_VERSION_CODE < KERNEL_VERSION(2,6,21)) ++static int michael_mic(struct ieee80211_tkip_data *tkey, u8 *key, u8 *hdr, ++ u8 *data, size_t data_len, u8 *mic) ++{ ++ struct scatterlist sg[2]; ++#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,20) ++ struct hash_desc desc; ++ int ret=0; ++#endif ++ if (tkey->tfm_michael == NULL) { ++ printk(KERN_WARNING "michael_mic: tfm_michael == NULL\n"); ++ return -1; ++ } ++ sg[0].page = virt_to_page(hdr); ++ sg[0].offset = offset_in_page(hdr); ++ sg[0].length = 16; ++ ++ sg[1].page = virt_to_page(data); ++ sg[1].offset = offset_in_page(data); ++ sg[1].length = data_len; ++ ++ //crypto_digest_init(tkey->tfm_michael); ++ //crypto_digest_setkey(tkey->tfm_michael, key, 8); ++ //crypto_digest_update(tkey->tfm_michael, sg, 2); ++ //crypto_digest_final(tkey->tfm_michael, mic); ++ ++ //return 0; ++#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,20) ++ crypto_digest_init(tkey->tfm_michael); ++ crypto_digest_setkey(tkey->tfm_michael, key, 8); ++ crypto_digest_update(tkey->tfm_michael, sg, 2); ++ crypto_digest_final(tkey->tfm_michael, mic); ++ ++ return 0; ++#else ++if (crypto_hash_setkey(tkey->tfm_michael, key, 8)) ++ return -1; ++ ++// return 0; ++ desc.tfm = tkey->tfm_michael; ++ desc.flags = 0; ++ ret = crypto_hash_digest(&desc, sg, data_len + 16, mic); ++ return ret; ++#endif ++} ++#else ++static int michael_mic(struct crypto_hash *tfm_michael, u8 * key, u8 * hdr, ++ u8 * data, size_t data_len, u8 * mic) ++{ ++ struct hash_desc desc; ++ struct scatterlist sg[2]; ++ ++ if (tfm_michael == NULL) { ++ printk(KERN_WARNING "michael_mic: tfm_michael == NULL\n"); ++ return -1; ++ } ++#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,24) ++ sg[0].page = virt_to_page(hdr); ++ sg[0].offset = offset_in_page(hdr); ++ sg[0].length = 16; ++ ++ sg[1].page = virt_to_page(data); ++ sg[1].offset = offset_in_page(data); ++ sg[1].length = data_len; ++#else ++ sg_init_table(sg, 2); ++ sg_set_buf(&sg[0], hdr, 16); ++ sg_set_buf(&sg[1], data, data_len); ++#endif ++ if (crypto_hash_setkey(tfm_michael, key, 8)) ++ return -1; ++ ++ desc.tfm = tfm_michael; ++ desc.flags = 0; ++ return crypto_hash_digest(&desc, sg, data_len + 16, mic); ++} ++#endif ++ ++ ++ ++static void michael_mic_hdr(struct sk_buff *skb, u8 *hdr) ++{ ++ struct ieee80211_hdr *hdr11; ++ ++ hdr11 = (struct ieee80211_hdr *) skb->data; ++ switch (le16_to_cpu(hdr11->frame_ctl) & ++ (IEEE80211_FCTL_FROMDS | IEEE80211_FCTL_TODS)) { ++ case IEEE80211_FCTL_TODS: ++ memcpy(hdr, hdr11->addr3, ETH_ALEN); /* DA */ ++ memcpy(hdr + ETH_ALEN, hdr11->addr2, ETH_ALEN); /* SA */ ++ break; ++ case IEEE80211_FCTL_FROMDS: ++ memcpy(hdr, hdr11->addr1, ETH_ALEN); /* DA */ ++ memcpy(hdr + ETH_ALEN, hdr11->addr3, ETH_ALEN); /* SA */ ++ break; ++ case IEEE80211_FCTL_FROMDS | IEEE80211_FCTL_TODS: ++ memcpy(hdr, hdr11->addr3, ETH_ALEN); /* DA */ ++ memcpy(hdr + ETH_ALEN, hdr11->addr4, ETH_ALEN); /* SA */ ++ break; ++ case 0: ++ memcpy(hdr, hdr11->addr1, ETH_ALEN); /* DA */ ++ memcpy(hdr + ETH_ALEN, hdr11->addr2, ETH_ALEN); /* SA */ ++ break; ++ } ++ ++ hdr[12] = 0; /* priority */ ++ ++ hdr[13] = hdr[14] = hdr[15] = 0; /* reserved */ ++} ++ ++ ++static int ieee80211_michael_mic_add(struct sk_buff *skb, int hdr_len, void *priv) ++{ ++ struct ieee80211_tkip_data *tkey = priv; ++ u8 *pos; ++ struct ieee80211_hdr *hdr; ++ ++ hdr = (struct ieee80211_hdr *) skb->data; ++ ++ if (skb_tailroom(skb) < 8 || skb->len < hdr_len) { ++ printk(KERN_DEBUG "Invalid packet for Michael MIC add " ++ "(tailroom=%d hdr_len=%d skb->len=%d)\n", ++ skb_tailroom(skb), hdr_len, skb->len); ++ return -1; ++ } ++ ++ michael_mic_hdr(skb, tkey->tx_hdr); ++ ++ // { david, 2006.9.1 ++ // fix the wpa process with wmm enabled. ++ if(IEEE80211_QOS_HAS_SEQ(le16_to_cpu(hdr->frame_ctl))) { ++ tkey->tx_hdr[12] = *(skb->data + hdr_len - 2) & 0x07; ++ } ++ // } ++ pos = skb_put(skb, 8); ++ #if(LINUX_VERSION_CODE < KERNEL_VERSION(2,6,21)) ++ if (michael_mic(tkey, &tkey->key[16], tkey->tx_hdr, ++ skb->data + hdr_len, skb->len - 8 - hdr_len, pos)) ++ #else ++ if (michael_mic(tkey->tx_tfm_michael, &tkey->key[16], tkey->tx_hdr, ++ skb->data + hdr_len, skb->len - 8 - hdr_len, pos)) ++ #endif ++ return -1; ++ ++ return 0; ++} ++ ++ ++#if WIRELESS_EXT >= 18 ++static void ieee80211_michael_mic_failure(struct net_device *dev, ++ struct ieee80211_hdr *hdr, ++ int keyidx) ++{ ++ union iwreq_data wrqu; ++ struct iw_michaelmicfailure ev; ++ ++ /* TODO: needed parameters: count, keyid, key type, TSC */ ++ memset(&ev, 0, sizeof(ev)); ++ ev.flags = keyidx & IW_MICFAILURE_KEY_ID; ++ if (hdr->addr1[0] & 0x01) ++ ev.flags |= IW_MICFAILURE_GROUP; ++ else ++ ev.flags |= IW_MICFAILURE_PAIRWISE; ++ ev.src_addr.sa_family = ARPHRD_ETHER; ++ memcpy(ev.src_addr.sa_data, hdr->addr2, ETH_ALEN); ++ memset(&wrqu, 0, sizeof(wrqu)); ++ wrqu.data.length = sizeof(ev); ++ wireless_send_event(dev, IWEVMICHAELMICFAILURE, &wrqu, (char *) &ev); ++} ++#elif WIRELESS_EXT >= 15 ++static void ieee80211_michael_mic_failure(struct net_device *dev, ++ struct ieee80211_hdr *hdr, ++ int keyidx) ++{ ++ union iwreq_data wrqu; ++ char buf[128]; ++ ++ /* TODO: needed parameters: count, keyid, key type, TSC */ ++ sprintf(buf, "MLME-MICHAELMICFAILURE.indication(keyid=%d %scast addr=" ++ MAC_FMT ")", keyidx, hdr->addr1[0] & 0x01 ? "broad" : "uni", ++ MAC_ARG(hdr->addr2)); ++ memset(&wrqu, 0, sizeof(wrqu)); ++ wrqu.data.length = strlen(buf); ++ wireless_send_event(dev, IWEVCUSTOM, &wrqu, buf); ++} ++#else /* WIRELESS_EXT >= 15 */ ++static inline void ieee80211_michael_mic_failure(struct net_device *dev, ++ struct ieee80211_hdr *hdr, ++ int keyidx) ++{ ++} ++#endif /* WIRELESS_EXT >= 15 */ ++ ++ ++static int ieee80211_michael_mic_verify(struct sk_buff *skb, int keyidx, ++ int hdr_len, void *priv) ++{ ++ struct ieee80211_tkip_data *tkey = priv; ++ u8 mic[8]; ++ struct ieee80211_hdr *hdr; ++ ++ hdr = (struct ieee80211_hdr *) skb->data; ++ ++ if (!tkey->key_set) ++ return -1; ++ ++ michael_mic_hdr(skb, tkey->rx_hdr); ++ // { david, 2006.9.1 ++ // fix the wpa process with wmm enabled. ++ if(IEEE80211_QOS_HAS_SEQ(le16_to_cpu(hdr->frame_ctl))) { ++ tkey->rx_hdr[12] = *(skb->data + hdr_len - 2) & 0x07; ++ } ++ // } ++ #if(LINUX_VERSION_CODE < KERNEL_VERSION(2,6,21)) ++ if (michael_mic(tkey, &tkey->key[24], tkey->rx_hdr, ++ skb->data + hdr_len, skb->len - 8 - hdr_len, mic)) ++ #else ++ if (michael_mic(tkey->rx_tfm_michael, &tkey->key[24], tkey->rx_hdr, ++ skb->data + hdr_len, skb->len - 8 - hdr_len, mic)) ++ #endif ++ return -1; ++ if (memcmp(mic, skb->data + skb->len - 8, 8) != 0) { ++ struct ieee80211_hdr *hdr; ++ hdr = (struct ieee80211_hdr *) skb->data; ++ printk(KERN_DEBUG "%s: Michael MIC verification failed for " ++ "MSDU from " MAC_FMT " keyidx=%d\n", ++ skb->dev ? skb->dev->name : "N/A", MAC_ARG(hdr->addr2), ++ keyidx); ++ if (skb->dev) ++ ieee80211_michael_mic_failure(skb->dev, hdr, keyidx); ++ tkey->dot11RSNAStatsTKIPLocalMICFailures++; ++ return -1; ++ } ++ ++ /* Update TSC counters for RX now that the packet verification has ++ * completed. */ ++ tkey->rx_iv32 = tkey->rx_iv32_new; ++ tkey->rx_iv16 = tkey->rx_iv16_new; ++ ++ skb_trim(skb, skb->len - 8); ++ ++ return 0; ++} ++ ++ ++static int ieee80211_tkip_set_key(void *key, int len, u8 *seq, void *priv) ++{ ++ struct ieee80211_tkip_data *tkey = priv; ++ int keyidx; ++ #if(LINUX_VERSION_CODE < KERNEL_VERSION(2,6,21)) ++ struct crypto_tfm *tfm = tkey->tfm_michael; ++ struct crypto_tfm *tfm2 = tkey->tfm_arc4; ++ #else ++ struct crypto_hash *tfm = tkey->tx_tfm_michael; ++ struct crypto_blkcipher *tfm2 = tkey->tx_tfm_arc4; ++ struct crypto_hash *tfm3 = tkey->rx_tfm_michael; ++ struct crypto_blkcipher *tfm4 = tkey->rx_tfm_arc4; ++ #endif ++ ++ keyidx = tkey->key_idx; ++ memset(tkey, 0, sizeof(*tkey)); ++ tkey->key_idx = keyidx; ++ ++ #if(LINUX_VERSION_CODE < KERNEL_VERSION(2,6,21)) ++ tkey->tfm_michael = tfm; ++ tkey->tfm_arc4 = tfm2; ++ #else ++ tkey->tx_tfm_michael = tfm; ++ tkey->tx_tfm_arc4 = tfm2; ++ tkey->rx_tfm_michael = tfm3; ++ tkey->rx_tfm_arc4 = tfm4; ++ #endif ++ ++ if (len == TKIP_KEY_LEN) { ++ memcpy(tkey->key, key, TKIP_KEY_LEN); ++ tkey->key_set = 1; ++ tkey->tx_iv16 = 1; /* TSC is initialized to 1 */ ++ if (seq) { ++ tkey->rx_iv32 = (seq[5] << 24) | (seq[4] << 16) | ++ (seq[3] << 8) | seq[2]; ++ tkey->rx_iv16 = (seq[1] << 8) | seq[0]; ++ } ++ } else if (len == 0) ++ tkey->key_set = 0; ++ else ++ return -1; ++ ++ return 0; ++} ++ ++ ++static int ieee80211_tkip_get_key(void *key, int len, u8 *seq, void *priv) ++{ ++ struct ieee80211_tkip_data *tkey = priv; ++ ++ if (len < TKIP_KEY_LEN) ++ return -1; ++ ++ if (!tkey->key_set) ++ return 0; ++ memcpy(key, tkey->key, TKIP_KEY_LEN); ++ ++ if (seq) { ++ /* Return the sequence number of the last transmitted frame. */ ++ u16 iv16 = tkey->tx_iv16; ++ u32 iv32 = tkey->tx_iv32; ++ if (iv16 == 0) ++ iv32--; ++ iv16--; ++ seq[0] = tkey->tx_iv16; ++ seq[1] = tkey->tx_iv16 >> 8; ++ seq[2] = tkey->tx_iv32; ++ seq[3] = tkey->tx_iv32 >> 8; ++ seq[4] = tkey->tx_iv32 >> 16; ++ seq[5] = tkey->tx_iv32 >> 24; ++ } ++ ++ return TKIP_KEY_LEN; ++} ++ ++ ++static char * ieee80211_tkip_print_stats(char *p, void *priv) ++{ ++ struct ieee80211_tkip_data *tkip = priv; ++ p += sprintf(p, "key[%d] alg=TKIP key_set=%d " ++ "tx_pn=%02x%02x%02x%02x%02x%02x " ++ "rx_pn=%02x%02x%02x%02x%02x%02x " ++ "replays=%d icv_errors=%d local_mic_failures=%d\n", ++ tkip->key_idx, tkip->key_set, ++ (tkip->tx_iv32 >> 24) & 0xff, ++ (tkip->tx_iv32 >> 16) & 0xff, ++ (tkip->tx_iv32 >> 8) & 0xff, ++ tkip->tx_iv32 & 0xff, ++ (tkip->tx_iv16 >> 8) & 0xff, ++ tkip->tx_iv16 & 0xff, ++ (tkip->rx_iv32 >> 24) & 0xff, ++ (tkip->rx_iv32 >> 16) & 0xff, ++ (tkip->rx_iv32 >> 8) & 0xff, ++ tkip->rx_iv32 & 0xff, ++ (tkip->rx_iv16 >> 8) & 0xff, ++ tkip->rx_iv16 & 0xff, ++ tkip->dot11RSNAStatsTKIPReplays, ++ tkip->dot11RSNAStatsTKIPICVErrors, ++ tkip->dot11RSNAStatsTKIPLocalMICFailures); ++ return p; ++} ++ ++ ++static struct ieee80211_crypto_ops ieee80211_crypt_tkip = { ++ .name = "TKIP", ++ .init = ieee80211_tkip_init, ++ .deinit = ieee80211_tkip_deinit, ++ .encrypt_mpdu = ieee80211_tkip_encrypt, ++ .decrypt_mpdu = ieee80211_tkip_decrypt, ++ .encrypt_msdu = ieee80211_michael_mic_add, ++ .decrypt_msdu = ieee80211_michael_mic_verify, ++ .set_key = ieee80211_tkip_set_key, ++ .get_key = ieee80211_tkip_get_key, ++ .print_stats = ieee80211_tkip_print_stats, ++ .extra_prefix_len = 4 + 4, /* IV + ExtIV */ ++ .extra_postfix_len = 8 + 4, /* MIC + ICV */ ++ .owner = THIS_MODULE, ++}; ++ ++ ++int __init ieee80211_crypto_tkip_init(void) ++{ ++ return ieee80211_register_crypto_ops(&ieee80211_crypt_tkip); ++} ++ ++ ++void __exit ieee80211_crypto_tkip_exit(void) ++{ ++ ieee80211_unregister_crypto_ops(&ieee80211_crypt_tkip); ++} ++ ++ ++void ieee80211_tkip_null(void) ++{ ++// printk("============>%s()\n", __FUNCTION__); ++ return; ++} ++ ++#if 0 ++#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0)) ++EXPORT_SYMBOL(ieee80211_tkip_null); ++#else ++EXPORT_SYMBOL_NOVERS(ieee80211_tkip_null); ++#endif ++ ++ ++module_init(ieee80211_crypto_tkip_init); ++module_exit(ieee80211_crypto_tkip_exit); ++#endif +diff -Nur linux-2.6.33/drivers/net/wireless/rtl8187b/ieee80211/ieee80211_crypt_wep.c linux-lemote/drivers/net/wireless/rtl8187b/ieee80211/ieee80211_crypt_wep.c +--- linux-2.6.33/drivers/net/wireless/rtl8187b/ieee80211/ieee80211_crypt_wep.c 1970-01-01 01:00:00.000000000 +0100 ++++ linux-lemote/drivers/net/wireless/rtl8187b/ieee80211/ieee80211_crypt_wep.c 2010-03-06 16:43:22.000000000 +0100 +@@ -0,0 +1,383 @@ ++/* ++ * Host AP crypt: host-based WEP encryption implementation for Host AP driver ++ * ++ * Copyright (c) 2002-2004, Jouni Malinen <jkmaline@cc.hut.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. See README and COPYING for ++ * more details. ++ */ ++ ++//#include <linux/config.h> ++#include <linux/version.h> ++#include <linux/module.h> ++#include <linux/init.h> ++#include <linux/slab.h> ++#include <linux/random.h> ++#include <linux/skbuff.h> ++#include <asm/string.h> ++ ++#include "ieee80211.h" ++ ++#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)) ++#include "rtl_crypto.h" ++#else ++#include <linux/crypto.h> ++#endif ++ ++#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,20) ++ #include <asm/scatterlist.h> ++#else ++ #include <linux/scatterlist.h> ++#endif ++//#include <asm/scatterlist.h> ++#include <linux/crc32.h> ++ ++MODULE_AUTHOR("Jouni Malinen"); ++MODULE_DESCRIPTION("Host AP crypt: WEP"); ++MODULE_LICENSE("GPL"); ++ ++ ++struct prism2_wep_data { ++ u32 iv; ++#define WEP_KEY_LEN 13 ++ u8 key[WEP_KEY_LEN + 1]; ++ u8 key_len; ++ u8 key_idx; ++ #if(LINUX_VERSION_CODE < KERNEL_VERSION(2,6,21)) ++ struct crypto_tfm *tfm; ++ #else ++ struct crypto_blkcipher *tx_tfm; ++ struct crypto_blkcipher *rx_tfm; ++ #endif ++}; ++ ++ ++static void * prism2_wep_init(int keyidx) ++{ ++ struct prism2_wep_data *priv; ++ ++ priv = kmalloc(sizeof(*priv), GFP_ATOMIC); ++ if (priv == NULL) ++ goto fail; ++ memset(priv, 0, sizeof(*priv)); ++ priv->key_idx = keyidx; ++ #if(LINUX_VERSION_CODE < KERNEL_VERSION(2,6,21)) ++ priv->tfm = crypto_alloc_tfm("arc4", 0); ++ if (priv->tfm == NULL) { ++ printk(KERN_DEBUG "ieee80211_crypt_wep: could not allocate " ++ "crypto API arc4\n"); ++ goto fail; ++ } ++ #else ++ priv->tx_tfm = crypto_alloc_blkcipher("ecb(arc4)", 0, CRYPTO_ALG_ASYNC); ++ if (IS_ERR(priv->tx_tfm)) { ++ printk(KERN_DEBUG "ieee80211_crypt_wep: could not allocate " ++ "crypto API arc4\n"); ++ priv->tx_tfm = NULL; ++ goto fail; ++ } ++ priv->rx_tfm = crypto_alloc_blkcipher("ecb(arc4)", 0, CRYPTO_ALG_ASYNC); ++ if (IS_ERR(priv->rx_tfm)) { ++ printk(KERN_DEBUG "ieee80211_crypt_wep: could not allocate " ++ "crypto API arc4\n"); ++ priv->rx_tfm = NULL; ++ goto fail; ++ } ++ #endif ++ ++ /* start WEP IV from a random value */ ++ get_random_bytes(&priv->iv, 4); ++ ++ return priv; ++ ++fail: ++ #if(LINUX_VERSION_CODE < KERNEL_VERSION(2,6,21)) ++ if (priv) { ++ if (priv->tfm) ++ crypto_free_tfm(priv->tfm); ++ kfree(priv); ++ } ++ #else ++ if (priv) { ++ if (priv->tx_tfm) ++ crypto_free_blkcipher(priv->tx_tfm); ++ if (priv->rx_tfm) ++ crypto_free_blkcipher(priv->rx_tfm); ++ kfree(priv); ++ } ++ #endif ++ return NULL; ++} ++ ++ ++static void prism2_wep_deinit(void *priv) ++{ ++ struct prism2_wep_data *_priv = priv; ++ #if(LINUX_VERSION_CODE < KERNEL_VERSION(2,6,21)) ++ if (_priv && _priv->tfm) ++ crypto_free_tfm(_priv->tfm); ++ #else ++ if (_priv) { ++ if (_priv->tx_tfm) ++ crypto_free_blkcipher(_priv->tx_tfm); ++ if (_priv->rx_tfm) ++ crypto_free_blkcipher(_priv->rx_tfm); ++ } ++ #endif ++ kfree(priv); ++} ++ ++ ++/* Perform WEP encryption on given skb that has at least 4 bytes of headroom ++ * for IV and 4 bytes of tailroom for ICV. Both IV and ICV will be transmitted, ++ * so the payload length increases with 8 bytes. ++ * ++ * WEP frame payload: IV + TX key idx, RC4(data), ICV = RC4(CRC32(data)) ++ */ ++static int prism2_wep_encrypt(struct sk_buff *skb, int hdr_len, void *priv) ++{ ++ struct prism2_wep_data *wep = priv; ++#if(LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,21)) ++ struct blkcipher_desc desc = {.tfm = wep->tx_tfm}; ++#endif ++ u32 klen, len; ++ u8 key[WEP_KEY_LEN + 3]; ++ u8 *pos; ++#ifndef JOHN_HWSEC ++ u32 crc; ++ u8 *icv; ++ struct scatterlist sg; ++#endif ++ if (skb_headroom(skb) < 4 || skb_tailroom(skb) < 4 || ++ skb->len < hdr_len) ++ return -1; ++ ++ len = skb->len - hdr_len; ++ pos = skb_push(skb, 4); ++ memmove(pos, pos + 4, hdr_len); ++ pos += hdr_len; ++ ++ klen = 3 + wep->key_len; ++ ++ wep->iv++; ++ ++ /* Fluhrer, Mantin, and Shamir have reported weaknesses in the key ++ * scheduling algorithm of RC4. At least IVs (KeyByte + 3, 0xff, N) ++ * can be used to speedup attacks, so avoid using them. */ ++ if ((wep->iv & 0xff00) == 0xff00) { ++ u8 B = (wep->iv >> 16) & 0xff; ++ if (B >= 3 && B < klen) ++ wep->iv += 0x0100; ++ } ++ ++ /* Prepend 24-bit IV to RC4 key and TX frame */ ++ *pos++ = key[0] = (wep->iv >> 16) & 0xff; ++ *pos++ = key[1] = (wep->iv >> 8) & 0xff; ++ *pos++ = key[2] = wep->iv & 0xff; ++ *pos++ = wep->key_idx << 6; ++ ++ /* Copy rest of the WEP key (the secret part) */ ++ memcpy(key + 3, wep->key, wep->key_len); ++ ++#ifndef JOHN_HWSEC ++ /* Append little-endian CRC32 and encrypt it to produce ICV */ ++#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0)) ++ crc = ~crc32_le(~0, pos, len); ++#else ++ crc = ~ether_crc_le(len, pos); ++#endif ++ icv = skb_put(skb, 4); ++ icv[0] = crc; ++ icv[1] = crc >> 8; ++ icv[2] = crc >> 16; ++ icv[3] = crc >> 24; ++ ++ #if(LINUX_VERSION_CODE < KERNEL_VERSION(2,6,21)) ++ crypto_cipher_setkey(wep->tfm, key, klen); ++ sg.page = virt_to_page(pos); ++ sg.offset = offset_in_page(pos); ++ sg.length = len + 4; ++ crypto_cipher_encrypt(wep->tfm, &sg, &sg, len + 4); ++ ++ return 0; ++ #else ++ crypto_blkcipher_setkey(wep->tx_tfm, key, klen); ++ #if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 24)) ++ sg.page = virt_to_page(pos); ++ sg.offset = offset_in_page(pos); ++ sg.length = len + 4; ++ #else ++ sg_init_one(&sg, pos, len + 4); ++ #endif ++ return crypto_blkcipher_encrypt(&desc, &sg, &sg, len + 4); ++ #endif ++#endif /* JOHN_HWSEC */ ++ return 0; ++} ++ ++ ++/* Perform WEP decryption on given buffer. Buffer includes whole WEP part of ++ * the frame: IV (4 bytes), encrypted payload (including SNAP header), ++ * ICV (4 bytes). len includes both IV and ICV. ++ * ++ * Returns 0 if frame was decrypted successfully and ICV was correct and -1 on ++ * failure. If frame is OK, IV and ICV will be removed. ++ */ ++static int prism2_wep_decrypt(struct sk_buff *skb, int hdr_len, void *priv) ++{ ++ struct prism2_wep_data *wep = priv; ++ #if(LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,21)) ++ struct blkcipher_desc desc = {.tfm = wep->rx_tfm}; ++ #endif ++ u32 klen, plen; ++ u8 key[WEP_KEY_LEN + 3]; ++ u8 keyidx, *pos; ++#ifndef JOHN_HWSEC ++ u32 crc; ++ u8 icv[4]; ++ struct scatterlist sg; ++#endif ++ if (skb->len < hdr_len + 8) ++ return -1; ++ ++ pos = skb->data + hdr_len; ++ key[0] = *pos++; ++ key[1] = *pos++; ++ key[2] = *pos++; ++ keyidx = *pos++ >> 6; ++ if (keyidx != wep->key_idx) ++ return -1; ++ ++ klen = 3 + wep->key_len; ++ ++ /* Copy rest of the WEP key (the secret part) */ ++ memcpy(key + 3, wep->key, wep->key_len); ++ ++ /* Apply RC4 to data and compute CRC32 over decrypted data */ ++ plen = skb->len - hdr_len - 8; ++#ifndef JOHN_HWSEC ++#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,21)) ++ crypto_cipher_setkey(wep->tfm, key, klen); ++ sg.page = virt_to_page(pos); ++ sg.offset = offset_in_page(pos); ++ sg.length = plen + 4; ++ crypto_cipher_decrypt(wep->tfm, &sg, &sg, plen + 4); ++#else ++ crypto_blkcipher_setkey(wep->rx_tfm, key, klen); ++ #if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,24)) ++ sg.page = virt_to_page(pos); ++ sg.offset = offset_in_page(pos); ++ sg.length = plen + 4; ++ #else ++ sg_init_one(&sg, pos, plen + 4); ++ #endif ++ if (crypto_blkcipher_decrypt(&desc, &sg, &sg, plen + 4)) ++ return -7; ++#endif ++ ++#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0)) ++ crc = ~crc32_le(~0, pos, plen); ++#else ++ crc = ~ether_crc_le(plen, pos); ++#endif ++ icv[0] = crc; ++ icv[1] = crc >> 8; ++ icv[2] = crc >> 16; ++ icv[3] = crc >> 24; ++ ++ if (memcmp(icv, pos + plen, 4) != 0) { ++ /* ICV mismatch - drop frame */ ++ return -2; ++ } ++#endif /* JOHN_HWSEC */ ++ ++ /* Remove IV and ICV */ ++ memmove(skb->data + 4, skb->data, hdr_len); ++ skb_pull(skb, 4); ++ skb_trim(skb, skb->len - 4); ++ return 0; ++} ++ ++ ++static int prism2_wep_set_key(void *key, int len, u8 *seq, void *priv) ++{ ++ struct prism2_wep_data *wep = priv; ++ ++ if (len < 0 || len > WEP_KEY_LEN) ++ return -1; ++ ++ memcpy(wep->key, key, len); ++ wep->key_len = len; ++ ++ return 0; ++} ++ ++ ++static int prism2_wep_get_key(void *key, int len, u8 *seq, void *priv) ++{ ++ struct prism2_wep_data *wep = priv; ++ ++ if (len < wep->key_len) ++ return -1; ++ ++ memcpy(key, wep->key, wep->key_len); ++ ++ return wep->key_len; ++} ++ ++ ++static char * prism2_wep_print_stats(char *p, void *priv) ++{ ++ struct prism2_wep_data *wep = priv; ++ p += sprintf(p, "key[%d] alg=WEP len=%d\n", ++ wep->key_idx, wep->key_len); ++ return p; ++} ++ ++ ++static struct ieee80211_crypto_ops ieee80211_crypt_wep = { ++ .name = "WEP", ++ .init = prism2_wep_init, ++ .deinit = prism2_wep_deinit, ++ .encrypt_mpdu = prism2_wep_encrypt, ++ .decrypt_mpdu = prism2_wep_decrypt, ++ .encrypt_msdu = NULL, ++ .decrypt_msdu = NULL, ++ .set_key = prism2_wep_set_key, ++ .get_key = prism2_wep_get_key, ++ .print_stats = prism2_wep_print_stats, ++ .extra_prefix_len = 4, /* IV */ ++ .extra_postfix_len = 4, /* ICV */ ++ .owner = THIS_MODULE, ++}; ++ ++ ++int __init ieee80211_crypto_wep_init(void) ++{ ++ return ieee80211_register_crypto_ops(&ieee80211_crypt_wep); ++} ++ ++ ++void __exit ieee80211_crypto_wep_exit(void) ++{ ++ ieee80211_unregister_crypto_ops(&ieee80211_crypt_wep); ++} ++ ++ ++void ieee80211_wep_null(void) ++{ ++// printk("============>%s()\n", __FUNCTION__); ++ return; ++} ++#if 0 ++#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0)) ++EXPORT_SYMBOL(ieee80211_wep_null); ++#else ++EXPORT_SYMBOL_NOVERS(ieee80211_wep_null); ++#endif ++ ++module_init(ieee80211_crypto_wep_init); ++module_exit(ieee80211_crypto_wep_exit); ++#endif +diff -Nur linux-2.6.33/drivers/net/wireless/rtl8187b/ieee80211/ieee80211.h linux-lemote/drivers/net/wireless/rtl8187b/ieee80211/ieee80211.h +--- linux-2.6.33/drivers/net/wireless/rtl8187b/ieee80211/ieee80211.h 1970-01-01 01:00:00.000000000 +0100 ++++ linux-lemote/drivers/net/wireless/rtl8187b/ieee80211/ieee80211.h 2010-03-06 16:43:22.000000000 +0100 +@@ -0,0 +1,1903 @@ ++/* ++ * Merged with mainline ieee80211.h in Aug 2004. Original ieee802_11 ++ * remains copyright by the original authors ++ * ++ * Portions of the merged code are based on Host AP (software wireless ++ * LAN access point) driver for Intersil Prism2/2.5/3. ++ * ++ * Copyright (c) 2001-2002, SSH Communications Security Corp and Jouni Malinen ++ * <jkmaline@cc.hut.fi> ++ * Copyright (c) 2002-2003, Jouni Malinen <jkmaline@cc.hut.fi> ++ * ++ * Adaption to a generic IEEE 802.11 stack by James Ketrenos ++ * <jketreno@linux.intel.com> ++ * Copyright (c) 2004, Intel Corporation ++ * ++ * Modified for Realtek's wi-fi cards by Andrea Merello ++ * <andreamrl@tiscali.it> ++ * ++ * 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. See README and COPYING for ++ * more details. ++ */ ++#ifndef IEEE80211_H ++#define IEEE80211_H ++#include <linux/if_ether.h> /* ETH_ALEN */ ++#include <linux/kernel.h> /* ARRAY_SIZE */ ++#include <linux/version.h> ++#include <linux/module.h> ++#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0)) ++#include <linux/jiffies.h> ++#else ++#include <linux/jffs.h> ++#include <linux/tqueue.h> ++#endif ++#include <linux/timer.h> ++#include <linux/sched.h> ++ ++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,13)) ++#include <linux/wireless.h> ++#endif ++/* ++#ifndef bool ++#define bool int ++#endif ++ ++#ifndef true ++#define true 1 ++#endif ++ ++#ifndef false ++#define false 0 ++#endif ++*/ ++#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,20)) ++#ifndef bool ++typedef enum{false = 0, true} bool; ++#endif ++#endif ++//#ifdef JOHN_HWSEC ++#define KEY_TYPE_NA 0x0 ++#define KEY_TYPE_WEP40 0x1 ++#define KEY_TYPE_TKIP 0x2 ++#define KEY_TYPE_CCMP 0x4 ++#define KEY_TYPE_WEP104 0x5 ++//#endif ++ ++ ++#define aSifsTime 10 ++ ++#define MGMT_QUEUE_NUM 5 ++ ++ ++#define IEEE_CMD_SET_WPA_PARAM 1 ++#define IEEE_CMD_SET_WPA_IE 2 ++#define IEEE_CMD_SET_ENCRYPTION 3 ++#define IEEE_CMD_MLME 4 ++ ++#define IEEE_PARAM_WPA_ENABLED 1 ++#define IEEE_PARAM_TKIP_COUNTERMEASURES 2 ++#define IEEE_PARAM_DROP_UNENCRYPTED 3 ++#define IEEE_PARAM_PRIVACY_INVOKED 4 ++#define IEEE_PARAM_AUTH_ALGS 5 ++#define IEEE_PARAM_IEEE_802_1X 6 ++//It should consistent with the driver_XXX.c ++// David, 2006.9.26 ++#define IEEE_PARAM_WPAX_SELECT 7 ++//Added for notify the encryption type selection ++// David, 2006.9.26 ++#define IEEE_PROTO_WPA 1 ++#define IEEE_PROTO_RSN 2 ++//Added for notify the encryption type selection ++// David, 2006.9.26 ++#define IEEE_WPAX_USEGROUP 0 ++#define IEEE_WPAX_WEP40 1 ++#define IEEE_WPAX_TKIP 2 ++#define IEEE_WPAX_WRAP 3 ++#define IEEE_WPAX_CCMP 4 ++#define IEEE_WPAX_WEP104 5 ++ ++#define IEEE_KEY_MGMT_IEEE8021X 1 ++#define IEEE_KEY_MGMT_PSK 2 ++ ++ ++ ++#define IEEE_MLME_STA_DEAUTH 1 ++#define IEEE_MLME_STA_DISASSOC 2 ++ ++ ++#define IEEE_CRYPT_ERR_UNKNOWN_ALG 2 ++#define IEEE_CRYPT_ERR_UNKNOWN_ADDR 3 ++#define IEEE_CRYPT_ERR_CRYPT_INIT_FAILED 4 ++#define IEEE_CRYPT_ERR_KEY_SET_FAILED 5 ++#define IEEE_CRYPT_ERR_TX_KEY_SET_FAILED 6 ++#define IEEE_CRYPT_ERR_CARD_CONF_FAILED 7 ++ ++ ++#define IEEE_CRYPT_ALG_NAME_LEN 16 ++ ++//#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,10)) ++#define ieee80211_wx_get_scan ieee80211_wx_get_scan_rtl ++#define ieee80211_wx_set_encode ieee80211_wx_set_encode_rtl ++#define ieee80211_wx_get_encode ieee80211_wx_get_encode_rtl ++//////////////////////////////// ++// added for kernel conflict under FC5 ++#define ieee80211_wx_get_name ieee80211_wx_get_name_rtl ++#define free_ieee80211 free_ieee80211_rtl ++#define alloc_ieee80211 alloc_ieee80211_rtl ++/////////////////////////////// ++//#endif ++#define ieee80211_rx ieee80211_rx_rtl ++#define ieee80211_wake_queue ieee80211_wake_queue_rtl ++#define ieee80211_stop_queue ieee80211_stop_queue_rtl ++#define ieee80211_wx_set_auth ieee80211_wx_set_auth_rtl ++#define ieee80211_get_crypto_ops ieee80211_get_crypto_ops_rtl ++#define ieee80211_crypt_delayed_deinit ieee80211_crypt_delayed_deinit_rtl ++ ++#define ieee80211_start_scan ieee80211_start_scan_rtl ++#define ieee80211_register_crypto_ops ieee80211_register_crypto_ops_rtl ++#define ieee80211_unregister_crypto_ops ieee80211_unregister_crypto_ops_rtl ++#define ieee80211_crypt_deinit_entries ieee80211_crypt_deinit_entries_rtl ++#define ieee80211_crypt_deinit_handler ieee80211_crypt_deinit_handler_rtl ++typedef struct ieee_param { ++ u32 cmd; ++ u8 sta_addr[ETH_ALEN]; ++ union { ++ struct { ++ u8 name; ++ u32 value; ++ } wpa_param; ++ struct { ++ u32 len; ++ u8 reserved[32]; ++ u8 data[0]; ++ } wpa_ie; ++ struct{ ++ int command; ++ int reason_code; ++ } mlme; ++ struct { ++ u8 alg[IEEE_CRYPT_ALG_NAME_LEN]; ++ u8 set_tx; ++ u32 err; ++ u8 idx; ++ u8 seq[8]; /* sequence counter (set: RX, get: TX) */ ++ u16 key_len; ++ u8 key[0]; ++ } crypt; ++ ++ } u; ++}ieee_param; ++ ++ ++#if WIRELESS_EXT < 17 ++#define IW_QUAL_QUAL_INVALID 0x10 ++#define IW_QUAL_LEVEL_INVALID 0x20 ++#define IW_QUAL_NOISE_INVALID 0x40 ++#define IW_QUAL_QUAL_UPDATED 0x1 ++#define IW_QUAL_LEVEL_UPDATED 0x2 ++#define IW_QUAL_NOISE_UPDATED 0x4 ++#endif ++ ++#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)) ++static inline void tq_init(struct tq_struct * task, void(*func)(void *), void *data) ++{ ++ task->routine = func; ++ task->data = data; ++ //task->next = NULL; ++ INIT_LIST_HEAD(&task->list); ++ task->sync = 0; ++} ++#endif ++ ++// linux under 2.6.9 release may not support it, so modify it for common use ++#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,9)) ++//#define MSECS(t) (1000 * ((t) / HZ) + 1000 * ((t) % HZ) / HZ) ++#define MSECS(t) (HZ * ((t) / 1000) + (HZ * ((t) % 1000)) / 1000) ++static inline unsigned long msleep_interruptible_rtl(unsigned int msecs) ++{ ++ unsigned long timeout = MSECS(msecs) + 1; ++ ++ while (timeout) { ++ set_current_state(TASK_UNINTERRUPTIBLE); ++ timeout = schedule_timeout(timeout); ++ } ++ return timeout; ++} ++#else ++#define MSECS(t) msecs_to_jiffies(t) ++#define msleep_interruptible_rtl msleep_interruptible ++#endif ++ ++#define IEEE80211_DATA_LEN 2304 ++/* Maximum size for the MA-UNITDATA primitive, 802.11 standard section ++ 6.2.1.1.2. ++ ++ The figure in section 7.1.2 suggests a body size of up to 2312 ++ bytes is allowed, which is a bit confusing, I suspect this ++ represents the 2304 bytes of real data, plus a possible 8 bytes of ++ WEP IV and ICV. (this interpretation suggested by Ramiro Barreiro) */ ++ ++ ++#define IEEE80211_HLEN 30 ++#define IEEE80211_FRAME_LEN (IEEE80211_DATA_LEN + IEEE80211_HLEN) ++ ++/* this is stolen and modified from the madwifi driver*/ ++#define IEEE80211_FC0_TYPE_MASK 0x0c ++#define IEEE80211_FC0_TYPE_DATA 0x08 ++#define IEEE80211_FC0_SUBTYPE_MASK 0xB0 ++#define IEEE80211_FC0_SUBTYPE_QOS 0x80 ++ ++#define IEEE80211_QOS_HAS_SEQ(fc) \ ++ (((fc) & (IEEE80211_FC0_TYPE_MASK | IEEE80211_FC0_SUBTYPE_MASK)) == \ ++ (IEEE80211_FC0_TYPE_DATA | IEEE80211_FC0_SUBTYPE_QOS)) ++ ++/* this is stolen from ipw2200 driver */ ++#define IEEE_IBSS_MAC_HASH_SIZE 31 ++#define IEEE_MESH_MAC_HASH_SIZE 31 ++struct ieee_ibss_seq { ++ u8 mac[ETH_ALEN]; ++ u16 seq_num[17]; ++ u16 frag_num[17]; ++ unsigned long packet_time[17]; ++ struct list_head list; ++}; ++ ++struct ieee_mesh_seq { ++ u8 mac[ETH_ALEN]; ++ u16 seq_num; ++ u16 frag_num; ++ unsigned long packet_time; ++ struct list_head list; ++}; ++ ++struct ieee80211_hdr { ++ u16 frame_ctl; ++ u16 duration_id; ++ u8 addr1[ETH_ALEN]; ++ u8 addr2[ETH_ALEN]; ++ u8 addr3[ETH_ALEN]; ++ u16 seq_ctl; ++ u8 addr4[ETH_ALEN]; ++} __attribute__ ((packed)); ++ ++struct ieee80211_hdr_QOS { ++ u16 frame_ctl; ++ u16 duration_id; ++ u8 addr1[ETH_ALEN]; ++ u8 addr2[ETH_ALEN]; ++ u8 addr3[ETH_ALEN]; ++ u16 seq_ctl; ++ u8 addr4[ETH_ALEN]; ++ u16 QOS_ctl; ++} __attribute__ ((packed)); ++ ++struct ieee80211_hdr_3addr { ++ u16 frame_ctl; ++ u16 duration_id; ++ u8 addr1[ETH_ALEN]; ++ u8 addr2[ETH_ALEN]; ++ u8 addr3[ETH_ALEN]; ++ u16 seq_ctl; ++} __attribute__ ((packed)); ++ ++struct ieee80211_hdr_3addr_QOS { ++ u16 frame_ctl; ++ u16 duration_id; ++ u8 addr1[ETH_ALEN]; ++ u8 addr2[ETH_ALEN]; ++ u8 addr3[ETH_ALEN]; ++ u16 seq_ctl; ++ u16 QOS_ctl; ++} __attribute__ ((packed)); ++ ++enum eap_type { ++ EAP_PACKET = 0, ++ EAPOL_START, ++ EAPOL_LOGOFF, ++ EAPOL_KEY, ++ EAPOL_ENCAP_ASF_ALERT ++}; ++ ++//by lizhaoming for LED 2008.6.23 from r8187_led.h ++#ifdef LED ++typedef enum _LED_CTL_MODE { ++ LED_CTL_POWER_ON, ++ LED_CTL_POWER_OFF, ++ LED_CTL_LINK, ++ LED_CTL_NO_LINK, ++ LED_CTL_TX, ++ LED_CTL_RX, ++ LED_CTL_SITE_SURVEY, ++} LED_CTL_MODE; ++#endif ++ ++static const char *eap_types[] = { ++ [EAP_PACKET] = "EAP-Packet", ++ [EAPOL_START] = "EAPOL-Start", ++ [EAPOL_LOGOFF] = "EAPOL-Logoff", ++ [EAPOL_KEY] = "EAPOL-Key", ++ [EAPOL_ENCAP_ASF_ALERT] = "EAPOL-Encap-ASF-Alert" ++}; ++ ++static inline const char *eap_get_type(int type) ++{ ++ return (type >= ARRAY_SIZE(eap_types)) ? "Unknown" : eap_types[type]; ++} ++ ++struct eapol { ++ u8 snap[6]; ++ u16 ethertype; ++ u8 version; ++ u8 type; ++ u16 length; ++} __attribute__ ((packed)); ++ ++#define IEEE80211_3ADDR_LEN 24 ++#define IEEE80211_4ADDR_LEN 30 ++#define IEEE80211_FCS_LEN 4 ++ ++#define MIN_FRAG_THRESHOLD 256U ++#define MAX_FRAG_THRESHOLD 2346U ++ ++/* Frame control field constants */ ++#define IEEE80211_FCTL_VERS 0x0002 ++#define IEEE80211_FCTL_FTYPE 0x000c ++#define IEEE80211_FCTL_STYPE 0x00f0 ++#define IEEE80211_FCTL_TODS 0x0100 ++#define IEEE80211_FCTL_FROMDS 0x0200 ++#define IEEE80211_FCTL_DSTODS 0x0300 //added by david ++#define IEEE80211_FCTL_MOREFRAGS 0x0400 ++#define IEEE80211_FCTL_RETRY 0x0800 ++#define IEEE80211_FCTL_PM 0x1000 ++#define IEEE80211_FCTL_MOREDATA 0x2000 ++#define IEEE80211_FCTL_WEP 0x4000 ++#define IEEE80211_FCTL_ORDER 0x8000 ++ ++#define IEEE80211_FTYPE_MGMT 0x0000 ++#define IEEE80211_FTYPE_CTL 0x0004 ++#define IEEE80211_FTYPE_DATA 0x0008 ++ ++/* management */ ++#define IEEE80211_STYPE_ASSOC_REQ 0x0000 ++#define IEEE80211_STYPE_ASSOC_RESP 0x0010 ++#define IEEE80211_STYPE_REASSOC_REQ 0x0020 ++#define IEEE80211_STYPE_REASSOC_RESP 0x0030 ++#define IEEE80211_STYPE_PROBE_REQ 0x0040 ++#define IEEE80211_STYPE_PROBE_RESP 0x0050 ++#define IEEE80211_STYPE_BEACON 0x0080 ++#define IEEE80211_STYPE_ATIM 0x0090 ++#define IEEE80211_STYPE_DISASSOC 0x00A0 ++#define IEEE80211_STYPE_AUTH 0x00B0 ++#define IEEE80211_STYPE_DEAUTH 0x00C0 ++#define IEEE80211_STYPE_MANAGE_ACT 0x00D0 ++ ++/* control */ ++#define IEEE80211_STYPE_PSPOLL 0x00A0 ++#define IEEE80211_STYPE_RTS 0x00B0 ++#define IEEE80211_STYPE_CTS 0x00C0 ++#define IEEE80211_STYPE_ACK 0x00D0 ++#define IEEE80211_STYPE_CFEND 0x00E0 ++#define IEEE80211_STYPE_CFENDACK 0x00F0 ++ ++/* data */ ++#define IEEE80211_STYPE_DATA 0x0000 ++#define IEEE80211_STYPE_DATA_CFACK 0x0010 ++#define IEEE80211_STYPE_DATA_CFPOLL 0x0020 ++#define IEEE80211_STYPE_DATA_CFACKPOLL 0x0030 ++#define IEEE80211_STYPE_NULLFUNC 0x0040 ++#define IEEE80211_STYPE_CFACK 0x0050 ++#define IEEE80211_STYPE_CFPOLL 0x0060 ++#define IEEE80211_STYPE_CFACKPOLL 0x0070 ++#define IEEE80211_STYPE_QOS_DATA 0x0080 //added for WMM 2006/8/2 ++#define IEEE80211_STYPE_QOS_NULL 0x00C0 ++ ++ ++#define IEEE80211_SCTL_FRAG 0x000F ++#define IEEE80211_SCTL_SEQ 0xFFF0 ++ ++ ++/* debug macros */ ++ ++#ifdef CONFIG_IEEE80211_DEBUG ++extern u32 ieee80211_debug_level; ++#define IEEE80211_DEBUG(level, fmt, args...) \ ++do { if (ieee80211_debug_level & (level)) \ ++ printk(KERN_DEBUG "ieee80211: %c %s " fmt, \ ++ in_interrupt() ? 'I' : 'U', __FUNCTION__ , ## args); } while (0) ++#else ++#define IEEE80211_DEBUG(level, fmt, args...) do {} while (0) ++#endif /* CONFIG_IEEE80211_DEBUG */ ++ ++/* ++ * To use the debug system; ++ * ++ * If you are defining a new debug classification, simply add it to the #define ++ * list here in the form of: ++ * ++ * #define IEEE80211_DL_xxxx VALUE ++ * ++ * shifting value to the left one bit from the previous entry. xxxx should be ++ * the name of the classification (for example, WEP) ++ * ++ * You then need to either add a IEEE80211_xxxx_DEBUG() macro definition for your ++ * classification, or use IEEE80211_DEBUG(IEEE80211_DL_xxxx, ...) whenever you want ++ * to send output to that classification. ++ * ++ * To add your debug level to the list of levels seen when you perform ++ * ++ * % cat /proc/net/ipw/debug_level ++ * ++ * you simply need to add your entry to the ipw_debug_levels array. ++ * ++ * If you do not see debug_level in /proc/net/ipw then you do not have ++ * CONFIG_IEEE80211_DEBUG defined in your kernel configuration ++ * ++ */ ++ ++#define IEEE80211_DL_INFO (1<<0) ++#define IEEE80211_DL_WX (1<<1) ++#define IEEE80211_DL_SCAN (1<<2) ++#define IEEE80211_DL_STATE (1<<3) ++#define IEEE80211_DL_MGMT (1<<4) ++#define IEEE80211_DL_FRAG (1<<5) ++#define IEEE80211_DL_EAP (1<<6) ++#define IEEE80211_DL_DROP (1<<7) ++ ++#define IEEE80211_DL_TX (1<<8) ++#define IEEE80211_DL_RX (1<<9) ++ ++#define IEEE80211_ERROR(f, a...) printk(KERN_ERR "ieee80211: " f, ## a) ++#define IEEE80211_WARNING(f, a...) printk(KERN_WARNING "ieee80211: " f, ## a) ++#define IEEE80211_DEBUG_INFO(f, a...) IEEE80211_DEBUG(IEEE80211_DL_INFO, f, ## a) ++ ++#define IEEE80211_DEBUG_WX(f, a...) IEEE80211_DEBUG(IEEE80211_DL_WX, f, ## a) ++#define IEEE80211_DEBUG_SCAN(f, a...) IEEE80211_DEBUG(IEEE80211_DL_SCAN, f, ## a) ++#define IEEE80211_DEBUG_STATE(f, a...) IEEE80211_DEBUG(IEEE80211_DL_STATE, f, ## a) ++#define IEEE80211_DEBUG_MGMT(f, a...) IEEE80211_DEBUG(IEEE80211_DL_MGMT, f, ## a) ++#define IEEE80211_DEBUG_FRAG(f, a...) IEEE80211_DEBUG(IEEE80211_DL_FRAG, f, ## a) ++#define IEEE80211_DEBUG_EAP(f, a...) IEEE80211_DEBUG(IEEE80211_DL_EAP, f, ## a) ++#define IEEE80211_DEBUG_DROP(f, a...) IEEE80211_DEBUG(IEEE80211_DL_DROP, f, ## a) ++#define IEEE80211_DEBUG_TX(f, a...) IEEE80211_DEBUG(IEEE80211_DL_TX, f, ## a) ++#define IEEE80211_DEBUG_RX(f, a...) IEEE80211_DEBUG(IEEE80211_DL_RX, f, ## a) ++#include <linux/netdevice.h> ++#include <linux/wireless.h> ++#include <linux/if_arp.h> /* ARPHRD_ETHER */ ++ ++#ifndef WIRELESS_SPY ++#define WIRELESS_SPY // enable iwspy support ++#endif ++#include <net/iw_handler.h> // new driver API ++ ++#ifndef ETH_P_PAE ++#define ETH_P_PAE 0x888E /* Port Access Entity (IEEE 802.1X) */ ++#endif /* ETH_P_PAE */ ++ ++#define ETH_P_PREAUTH 0x88C7 /* IEEE 802.11i pre-authentication */ ++ ++#ifndef ETH_P_80211_RAW ++#define ETH_P_80211_RAW (ETH_P_ECONET + 1) ++#endif ++ ++/* IEEE 802.11 defines */ ++ ++#define P80211_OUI_LEN 3 ++ ++struct ieee80211_snap_hdr { ++ ++ u8 dsap; /* always 0xAA */ ++ u8 ssap; /* always 0xAA */ ++ u8 ctrl; /* always 0x03 */ ++ u8 oui[P80211_OUI_LEN]; /* organizational universal id */ ++ ++} __attribute__ ((packed)); ++ ++#define SNAP_SIZE sizeof(struct ieee80211_snap_hdr) ++ ++#define WLAN_FC_GET_TYPE(fc) ((fc) & IEEE80211_FCTL_FTYPE) ++#define WLAN_FC_GET_STYPE(fc) ((fc) & IEEE80211_FCTL_STYPE) ++ ++#define WLAN_GET_SEQ_FRAG(seq) ((seq) & IEEE80211_SCTL_FRAG) ++#define WLAN_GET_SEQ_SEQ(seq) ((seq) & IEEE80211_SCTL_SEQ) ++ ++/* Authentication algorithms */ ++#define WLAN_AUTH_OPEN 0 ++#define WLAN_AUTH_SHARED_KEY 1 ++ ++#define WLAN_AUTH_CHALLENGE_LEN 128 ++ ++#define WLAN_CAPABILITY_BSS (1<<0) ++#define WLAN_CAPABILITY_IBSS (1<<1) ++#define WLAN_CAPABILITY_CF_POLLABLE (1<<2) ++#define WLAN_CAPABILITY_CF_POLL_REQUEST (1<<3) ++#define WLAN_CAPABILITY_PRIVACY (1<<4) ++#define WLAN_CAPABILITY_SHORT_PREAMBLE (1<<5) ++#define WLAN_CAPABILITY_PBCC (1<<6) ++#define WLAN_CAPABILITY_CHANNEL_AGILITY (1<<7) ++#define WLAN_CAPABILITY_SHORT_SLOT (1<<10) ++ ++/* Status codes */ ++#define WLAN_STATUS_SUCCESS 0 ++#define WLAN_STATUS_UNSPECIFIED_FAILURE 1 ++#define WLAN_STATUS_CAPS_UNSUPPORTED 10 ++#define WLAN_STATUS_REASSOC_NO_ASSOC 11 ++#define WLAN_STATUS_ASSOC_DENIED_UNSPEC 12 ++#define WLAN_STATUS_NOT_SUPPORTED_AUTH_ALG 13 ++#define WLAN_STATUS_UNKNOWN_AUTH_TRANSACTION 14 ++#define WLAN_STATUS_CHALLENGE_FAIL 15 ++#define WLAN_STATUS_AUTH_TIMEOUT 16 ++#define WLAN_STATUS_AP_UNABLE_TO_HANDLE_NEW_STA 17 ++#define WLAN_STATUS_ASSOC_DENIED_RATES 18 ++/* 802.11b */ ++#define WLAN_STATUS_ASSOC_DENIED_NOSHORT 19 ++#define WLAN_STATUS_ASSOC_DENIED_NOPBCC 20 ++#define WLAN_STATUS_ASSOC_DENIED_NOAGILITY 21 ++ ++/* Reason codes */ ++#define WLAN_REASON_UNSPECIFIED 1 ++#define WLAN_REASON_PREV_AUTH_NOT_VALID 2 ++#define WLAN_REASON_DEAUTH_LEAVING 3 ++#define WLAN_REASON_DISASSOC_DUE_TO_INACTIVITY 4 ++#define WLAN_REASON_DISASSOC_AP_BUSY 5 ++#define WLAN_REASON_CLASS2_FRAME_FROM_NONAUTH_STA 6 ++#define WLAN_REASON_CLASS3_FRAME_FROM_NONASSOC_STA 7 ++#define WLAN_REASON_DISASSOC_STA_HAS_LEFT 8 ++#define WLAN_REASON_STA_REQ_ASSOC_WITHOUT_AUTH 9 ++ ++ ++/* Information Element IDs */ ++#define WLAN_EID_SSID 0 ++#define WLAN_EID_SUPP_RATES 1 ++#define WLAN_EID_FH_PARAMS 2 ++#define WLAN_EID_DS_PARAMS 3 ++#define WLAN_EID_CF_PARAMS 4 ++#define WLAN_EID_TIM 5 ++#define WLAN_EID_IBSS_PARAMS 6 ++#define WLAN_EID_CHALLENGE 16 ++#define WLAN_EID_RSN 48 ++#define WLAN_EID_GENERIC 221 ++ ++#define IEEE80211_MGMT_HDR_LEN 24 ++#define IEEE80211_DATA_HDR3_LEN 24 ++#define IEEE80211_DATA_HDR4_LEN 30 ++ ++ ++#define IEEE80211_STATMASK_SIGNAL (1<<0) ++#define IEEE80211_STATMASK_RSSI (1<<1) ++#define IEEE80211_STATMASK_NOISE (1<<2) ++#define IEEE80211_STATMASK_RATE (1<<3) ++#define IEEE80211_STATMASK_WEMASK 0x7 ++ ++ ++#define IEEE80211_CCK_MODULATION (1<<0) ++#define IEEE80211_OFDM_MODULATION (1<<1) ++ ++#define IEEE80211_24GHZ_BAND (1<<0) ++#define IEEE80211_52GHZ_BAND (1<<1) ++ ++#define IEEE80211_CCK_RATE_LEN 4 ++#define IEEE80211_CCK_RATE_1MB 0x02 ++#define IEEE80211_CCK_RATE_2MB 0x04 ++#define IEEE80211_CCK_RATE_5MB 0x0B ++#define IEEE80211_CCK_RATE_11MB 0x16 ++#define IEEE80211_OFDM_RATE_LEN 8 ++#define IEEE80211_OFDM_RATE_6MB 0x0C ++#define IEEE80211_OFDM_RATE_9MB 0x12 ++#define IEEE80211_OFDM_RATE_12MB 0x18 ++#define IEEE80211_OFDM_RATE_18MB 0x24 ++#define IEEE80211_OFDM_RATE_24MB 0x30 ++#define IEEE80211_OFDM_RATE_36MB 0x48 ++#define IEEE80211_OFDM_RATE_48MB 0x60 ++#define IEEE80211_OFDM_RATE_54MB 0x6C ++#define IEEE80211_BASIC_RATE_MASK 0x80 ++ ++#define IEEE80211_CCK_RATE_1MB_MASK (1<<0) ++#define IEEE80211_CCK_RATE_2MB_MASK (1<<1) ++#define IEEE80211_CCK_RATE_5MB_MASK (1<<2) ++#define IEEE80211_CCK_RATE_11MB_MASK (1<<3) ++#define IEEE80211_OFDM_RATE_6MB_MASK (1<<4) ++#define IEEE80211_OFDM_RATE_9MB_MASK (1<<5) ++#define IEEE80211_OFDM_RATE_12MB_MASK (1<<6) ++#define IEEE80211_OFDM_RATE_18MB_MASK (1<<7) ++#define IEEE80211_OFDM_RATE_24MB_MASK (1<<8) ++#define IEEE80211_OFDM_RATE_36MB_MASK (1<<9) ++#define IEEE80211_OFDM_RATE_48MB_MASK (1<<10) ++#define IEEE80211_OFDM_RATE_54MB_MASK (1<<11) ++ ++#define IEEE80211_CCK_RATES_MASK 0x0000000F ++#define IEEE80211_CCK_BASIC_RATES_MASK (IEEE80211_CCK_RATE_1MB_MASK | \ ++ IEEE80211_CCK_RATE_2MB_MASK) ++#define IEEE80211_CCK_DEFAULT_RATES_MASK (IEEE80211_CCK_BASIC_RATES_MASK | \ ++ IEEE80211_CCK_RATE_5MB_MASK | \ ++ IEEE80211_CCK_RATE_11MB_MASK) ++ ++#define IEEE80211_OFDM_RATES_MASK 0x00000FF0 ++#define IEEE80211_OFDM_BASIC_RATES_MASK (IEEE80211_OFDM_RATE_6MB_MASK | \ ++ IEEE80211_OFDM_RATE_12MB_MASK | \ ++ IEEE80211_OFDM_RATE_24MB_MASK) ++#define IEEE80211_OFDM_DEFAULT_RATES_MASK (IEEE80211_OFDM_BASIC_RATES_MASK | \ ++ IEEE80211_OFDM_RATE_9MB_MASK | \ ++ IEEE80211_OFDM_RATE_18MB_MASK | \ ++ IEEE80211_OFDM_RATE_36MB_MASK | \ ++ IEEE80211_OFDM_RATE_48MB_MASK | \ ++ IEEE80211_OFDM_RATE_54MB_MASK) ++#define IEEE80211_DEFAULT_RATES_MASK (IEEE80211_OFDM_DEFAULT_RATES_MASK | \ ++ IEEE80211_CCK_DEFAULT_RATES_MASK) ++ ++#define IEEE80211_NUM_OFDM_RATES 8 ++#define IEEE80211_NUM_CCK_RATES 4 ++#define IEEE80211_OFDM_SHIFT_MASK_A 4 ++ ++ ++ ++ ++/* NOTE: This data is for statistical purposes; not all hardware provides this ++ * information for frames received. Not setting these will not cause ++ * any adverse affects. */ ++struct ieee80211_rx_stats { ++ u32 mac_time[2]; ++ u8 signalstrength; ++ s8 rssi; ++ u8 signal; ++ u8 noise; ++ u16 rate; /* in 100 kbps */ ++ u8 received_channel; ++ u8 control; ++ u8 mask; ++ u8 freq; ++ u16 len; ++ u8 nic_type; ++}; ++ ++/* IEEE 802.11 requires that STA supports concurrent reception of at least ++ * three fragmented frames. This define can be increased to support more ++ * concurrent frames, but it should be noted that each entry can consume about ++ * 2 kB of RAM and increasing cache size will slow down frame reassembly. */ ++#define IEEE80211_FRAG_CACHE_LEN 4 ++ ++struct ieee80211_frag_entry { ++ unsigned long first_frag_time; ++ unsigned int seq; ++ unsigned int last_frag; ++ struct sk_buff *skb; ++ u8 src_addr[ETH_ALEN]; ++ u8 dst_addr[ETH_ALEN]; ++}; ++ ++struct ieee80211_stats { ++ unsigned int tx_unicast_frames; ++ unsigned int tx_multicast_frames; ++ unsigned int tx_fragments; ++ unsigned int tx_unicast_octets; ++ unsigned int tx_multicast_octets; ++ unsigned int tx_deferred_transmissions; ++ unsigned int tx_single_retry_frames; ++ unsigned int tx_multiple_retry_frames; ++ unsigned int tx_retry_limit_exceeded; ++ unsigned int tx_discards; ++ unsigned int rx_unicast_frames; ++ unsigned int rx_multicast_frames; ++ unsigned int rx_fragments; ++ unsigned int rx_unicast_octets; ++ unsigned int rx_multicast_octets; ++ unsigned int rx_fcs_errors; ++ unsigned int rx_discards_no_buffer; ++ unsigned int tx_discards_wrong_sa; ++ unsigned int rx_discards_undecryptable; ++ unsigned int rx_message_in_msg_fragments; ++ unsigned int rx_message_in_bad_msg_fragments; ++}; ++ ++struct ieee80211_softmac_stats{ ++ unsigned int rx_ass_ok; ++ unsigned int rx_ass_err; ++ unsigned int rx_probe_rq; ++ unsigned int tx_probe_rs; ++ unsigned int tx_beacons; ++ unsigned int rx_auth_rq; ++ unsigned int rx_auth_rs_ok; ++ unsigned int rx_auth_rs_err; ++ unsigned int tx_auth_rq; ++ unsigned int no_auth_rs; ++ unsigned int no_ass_rs; ++ unsigned int tx_ass_rq; ++ unsigned int rx_ass_rq; ++ unsigned int tx_probe_rq; ++ unsigned int reassoc; ++ unsigned int swtxstop; ++ unsigned int swtxawake; ++}; ++ ++struct ieee80211_device; ++ ++#include "ieee80211_crypt.h" ++ ++#define SEC_KEY_1 (1<<0) ++#define SEC_KEY_2 (1<<1) ++#define SEC_KEY_3 (1<<2) ++#define SEC_KEY_4 (1<<3) ++#define SEC_ACTIVE_KEY (1<<4) ++#define SEC_AUTH_MODE (1<<5) ++#define SEC_UNICAST_GROUP (1<<6) ++#define SEC_LEVEL (1<<7) ++#define SEC_ENABLED (1<<8) ++ ++#define SEC_LEVEL_0 0 /* None */ ++#define SEC_LEVEL_1 1 /* WEP 40 and 104 bit */ ++#define SEC_LEVEL_2 2 /* Level 1 + TKIP */ ++#define SEC_LEVEL_2_CKIP 3 /* Level 1 + CKIP */ ++#define SEC_LEVEL_3 4 /* Level 2 + CCMP */ ++ ++#define WEP_KEYS 4 ++#define WEP_KEY_LEN 13 ++#define ALG_KEY_LEN 32 ++ ++#ifdef _RTL8187_EXT_PATCH_ ++#define MAX_MP 16 ++#endif ++struct ieee80211_security { ++ u16 active_key:2, ++ enabled:1, ++ auth_mode:2, ++ auth_algo:4, ++ unicast_uses_group:1; ++ u8 key_sizes[WEP_KEYS]; ++ u8 keys[WEP_KEYS][ALG_KEY_LEN]; ++ u8 level; ++ u16 flags; ++} __attribute__ ((packed)); ++ ++ ++/* ++ ++ 802.11 data frame from AP ++ ++ ,-------------------------------------------------------------------. ++Bytes | 2 | 2 | 6 | 6 | 6 | 2 | 0..2312 | 4 | ++ |------|------|---------|---------|---------|------|---------|------| ++Desc. | ctrl | dura | DA/RA | TA | SA | Sequ | frame | fcs | ++ | | tion | (BSSID) | | | ence | data | | ++ `-------------------------------------------------------------------' ++ ++Total: 28-2340 bytes ++ ++*/ ++ ++struct ieee80211_header_data { ++ u16 frame_ctl; ++ u16 duration_id; ++ u8 addr1[6]; ++ u8 addr2[6]; ++ u8 addr3[6]; ++ u16 seq_ctrl; ++}; ++ ++#define BEACON_PROBE_SSID_ID_POSITION 12 ++ ++/* Management Frame Information Element Types */ ++#define MFIE_TYPE_SSID 0 ++#define MFIE_TYPE_RATES 1 ++#define MFIE_TYPE_FH_SET 2 ++#define MFIE_TYPE_DS_SET 3 ++#define MFIE_TYPE_CF_SET 4 ++#define MFIE_TYPE_TIM 5 ++#define MFIE_TYPE_IBSS_SET 6 ++#define MFIE_TYPE_COUNTRY 7 ++#define MFIE_TYPE_CHALLENGE 16 ++#define MFIE_TYPE_ERP 42 ++#define MFIE_TYPE_RSN 48 ++#define MFIE_TYPE_RATES_EX 50 ++#define MFIE_TYPE_GENERIC 221 ++ ++#ifdef ENABLE_DOT11D ++typedef enum ++{ ++ COUNTRY_CODE_FCC = 0, ++ COUNTRY_CODE_IC = 1, ++ COUNTRY_CODE_ETSI = 2, ++ COUNTRY_CODE_SPAIN = 3, ++ COUNTRY_CODE_FRANCE = 4, ++ COUNTRY_CODE_MKK = 5, ++ COUNTRY_CODE_MKK1 = 6, ++ COUNTRY_CODE_ISRAEL = 7, ++ COUNTRY_CODE_TELEC = 8, ++ COUNTRY_CODE_GLOBAL_DOMAIN = 9, ++ COUNTRY_CODE_WORLD_WIDE_13_INDEX = 10 ++}country_code_type_t; ++#endif ++ ++ ++struct ieee80211_info_element_hdr { ++ u8 id; ++ u8 len; ++} __attribute__ ((packed)); ++ ++struct ieee80211_info_element { ++ u8 id; ++ u8 len; ++ u8 data[0]; ++} __attribute__ ((packed)); ++ ++/* ++ * These are the data types that can make up management packets ++ * ++ u16 auth_algorithm; ++ u16 auth_sequence; ++ u16 beacon_interval; ++ u16 capability; ++ u8 current_ap[ETH_ALEN]; ++ u16 listen_interval; ++ struct { ++ u16 association_id:14, reserved:2; ++ } __attribute__ ((packed)); ++ u32 time_stamp[2]; ++ u16 reason; ++ u16 status; ++*/ ++ ++#define IEEE80211_DEFAULT_TX_ESSID "Penguin" ++#define IEEE80211_DEFAULT_BASIC_RATE 10 ++#define IEEE80211_DEFAULT_MESHID "802.11s" ++#define IEEE80211_DEFAULT_MESH_CHAN 1 ++ ++struct ieee80211_authentication { ++ struct ieee80211_header_data header; ++ u16 algorithm; ++ u16 transaction; ++ u16 status; ++ //struct ieee80211_info_element_hdr info_element; ++} __attribute__ ((packed)); ++ ++ ++struct ieee80211_probe_response { ++ struct ieee80211_header_data header; ++ u32 time_stamp[2]; ++ u16 beacon_interval; ++ u16 capability; ++ struct ieee80211_info_element info_element; ++} __attribute__ ((packed)); ++ ++struct ieee80211_probe_request { ++ struct ieee80211_header_data header; ++ /*struct ieee80211_info_element info_element;*/ ++} __attribute__ ((packed)); ++ ++struct ieee80211_assoc_request_frame { ++ struct ieee80211_hdr_3addr header; ++ u16 capability; ++ u16 listen_interval; ++ //u8 current_ap[ETH_ALEN]; ++ struct ieee80211_info_element_hdr info_element; ++} __attribute__ ((packed)); ++ ++struct ieee80211_assoc_response_frame { ++ struct ieee80211_hdr_3addr header; ++ u16 capability; ++ u16 status; ++ u16 aid; ++ struct ieee80211_info_element info_element; /* supported rates */ ++} __attribute__ ((packed)); ++ ++ ++struct ieee80211_txb { ++ u8 nr_frags; ++ u8 encrypted; ++ u16 reserved; ++ u16 frag_size; ++ u16 payload_size; ++ struct sk_buff *fragments[0]; ++}; ++ ++struct ieee80211_wmm_ac_param { ++ u8 ac_aci_acm_aifsn; ++ u8 ac_ecwmin_ecwmax; ++ u16 ac_txop_limit; ++}; ++ ++struct ieee80211_wmm_ts_info { ++ u8 ac_dir_tid; ++ u8 ac_up_psb; ++ u8 reserved; ++} __attribute__ ((packed)); ++ ++struct ieee80211_wmm_tspec_elem { ++ struct ieee80211_wmm_ts_info ts_info; ++ u16 norm_msdu_size; ++ u16 max_msdu_size; ++ u32 min_serv_inter; ++ u32 max_serv_inter; ++ u32 inact_inter; ++ u32 suspen_inter; ++ u32 serv_start_time; ++ u32 min_data_rate; ++ u32 mean_data_rate; ++ u32 peak_data_rate; ++ u32 max_burst_size; ++ u32 delay_bound; ++ u32 min_phy_rate; ++ u16 surp_band_allow; ++ u16 medium_time; ++}__attribute__((packed)); ++ ++enum {WMM_all_frame, WMM_two_frame, WMM_four_frame, WMM_six_frame}; ++#define MAX_SP_Len (WMM_all_frame << 4) ++#define IEEE80211_QOS_TID 0x0f ++#define QOS_CTL_NOTCONTAIN_ACK (0x01 << 5) ++ ++/* SWEEP TABLE ENTRIES NUMBER*/ ++#define MAX_SWEEP_TAB_ENTRIES 42 ++#define MAX_SWEEP_TAB_ENTRIES_PER_PACKET 7 ++/* MAX_RATES_LENGTH needs to be 12. The spec says 8, and many APs ++ * only use 8, and then use extended rates for the remaining supported ++ * rates. Other APs, however, stick all of their supported rates on the ++ * main rates information element... */ ++#define MAX_RATES_LENGTH ((u8)12) ++#define MAX_RATES_EX_LENGTH ((u8)16) ++#define MAX_NETWORK_COUNT 128 ++#ifdef ENABLE_DOT11D ++#define MAX_CHANNEL_NUMBER 165 //YJ,modified,080625 ++#define MAX_IE_LEN 0xFF //+YJ,080625 ++#else ++#define MAX_CHANNEL_NUMBER 161 ++#endif ++ ++//#define IEEE80211_SOFTMAC_SCAN_TIME 400 ++#define IEEE80211_SOFTMAC_SCAN_TIME 100//lzm mod 081209 ++//(HZ / 2) ++#define IEEE80211_SOFTMAC_ASSOC_RETRY_TIME (HZ * 2) ++ ++#define CRC_LENGTH 4U ++ ++#define MAX_WPA_IE_LEN 64 ++ ++#define NETWORK_EMPTY_ESSID (1<<0) ++#define NETWORK_HAS_OFDM (1<<1) ++#define NETWORK_HAS_CCK (1<<2) ++ ++#define IEEE80211_DTIM_MBCAST 4 ++#define IEEE80211_DTIM_UCAST 2 ++#define IEEE80211_DTIM_VALID 1 ++#define IEEE80211_DTIM_INVALID 0 ++ ++#define IEEE80211_PS_DISABLED 0 ++#define IEEE80211_PS_UNICAST IEEE80211_DTIM_UCAST ++#define IEEE80211_PS_MBCAST IEEE80211_DTIM_MBCAST ++ ++//added by David for QoS 2006/6/30 ++//#define WMM_Hang_8187 ++#ifdef WMM_Hang_8187 ++#undef WMM_Hang_8187 ++#endif ++ ++#define WME_AC_BE 0x00 ++#define WME_AC_BK 0x01 ++#define WME_AC_VI 0x02 ++#define WME_AC_VO 0x03 ++#define WME_ACI_MASK 0x03 ++#define WME_AIFSN_MASK 0x03 ++#define WME_AC_PRAM_LEN 16 ++ ++//UP Mapping to AC, using in MgntQuery_SequenceNumber() and maybe for DSCP ++//#define UP2AC(up) ((up<3) ? ((up==0)?1:0) : (up>>1)) ++#define UP2AC(up) ( \ ++ ((up) < 1) ? WME_AC_BE : \ ++ ((up) < 3) ? WME_AC_BK : \ ++ ((up) < 4) ? WME_AC_BE : \ ++ ((up) < 6) ? WME_AC_VI : \ ++ WME_AC_VO) ++//AC Mapping to UP, using in Tx part for selecting the corresponding TX queue ++#define AC2UP(_ac) ( \ ++ ((_ac) == WME_AC_VO) ? 6 : \ ++ ((_ac) == WME_AC_VI) ? 5 : \ ++ ((_ac) == WME_AC_BK) ? 1 : \ ++ 0) ++ ++#define ETHER_ADDR_LEN 6 /* length of an Ethernet address */ ++struct ether_header { ++ u8 ether_dhost[ETHER_ADDR_LEN]; ++ u8 ether_shost[ETHER_ADDR_LEN]; ++ u16 ether_type; ++} __attribute__((packed)); ++ ++#ifndef ETHERTYPE_PAE ++#define ETHERTYPE_PAE 0x888e /* EAPOL PAE/802.1x */ ++#endif ++#ifndef ETHERTYPE_IP ++#define ETHERTYPE_IP 0x0800 /* IP protocol */ ++#endif ++ ++struct ieee80211_network { ++ /* These entries are used to identify a unique network */ ++ u8 bssid[ETH_ALEN]; ++ u8 channel; ++ /* Ensure null-terminated for any debug msgs */ ++ u8 ssid[IW_ESSID_MAX_SIZE + 1]; ++ u8 ssid_len; ++ ++ /* These are network statistics */ ++ struct ieee80211_rx_stats stats; ++ u16 capability; ++ u8 rates[MAX_RATES_LENGTH]; ++ u8 rates_len; ++ u8 rates_ex[MAX_RATES_EX_LENGTH]; ++ u8 rates_ex_len; ++ unsigned long last_scanned; ++ u8 mode; ++ u8 flags; ++ u32 last_associate; ++ u32 time_stamp[2]; ++ u16 beacon_interval; ++ u16 listen_interval; ++ u16 atim_window; ++ u8 wpa_ie[MAX_WPA_IE_LEN]; ++ size_t wpa_ie_len; ++ u8 rsn_ie[MAX_WPA_IE_LEN]; ++ size_t rsn_ie_len; ++ u8 dtim_period; ++ u8 dtim_data; ++ u32 last_dtim_sta_time[2]; ++#ifdef _RTL8187_EXT_PATCH_ ++ void *ext_entry; ++#endif ++ struct list_head list; ++ //appeded for QoS ++ u8 wmm_info; ++ struct ieee80211_wmm_ac_param wmm_param[4]; ++ u8 QoS_Enable; ++ u8 SignalStrength; ++#ifdef THOMAS_TURBO ++ u8 Turbo_Enable;//enable turbo mode, added by thomas ++#endif ++ ++#ifdef ENABLE_DOT11D ++ u16 CountryIeLen; ++ u8 CountryIeBuf[MAX_IE_LEN]; ++#endif ++ ++}; ++ ++enum ieee80211_state { ++ ++ /* the card is not linked at all */ ++ IEEE80211_NOLINK = 0, ++ ++ /* IEEE80211_ASSOCIATING* are for BSS client mode ++ * the driver shall not perform RX filtering unless ++ * the state is LINKED. ++ * The driver shall just check for the state LINKED and ++ * defaults to NOLINK for ALL the other states (including ++ * LINKED_SCANNING) ++ */ ++ ++ /* the association procedure will start (wq scheduling)*/ ++ IEEE80211_ASSOCIATING, ++ IEEE80211_ASSOCIATING_RETRY, ++ ++ /* the association procedure is sending AUTH request*/ ++ IEEE80211_ASSOCIATING_AUTHENTICATING, ++ ++ /* the association procedure has successfully authentcated ++ * and is sending association request ++ */ ++ IEEE80211_ASSOCIATING_AUTHENTICATED, ++ ++ /* the link is ok. the card associated to a BSS or linked ++ * to a ibss cell or acting as an AP and creating the bss ++ */ ++ IEEE80211_LINKED, ++ ++ /* same as LINKED, but the driver shall apply RX filter ++ * rules as we are in NO_LINK mode. As the card is still ++ * logically linked, but it is doing a syncro site survey ++ * then it will be back to LINKED state. ++ */ ++ IEEE80211_LINKED_SCANNING, ++//by amy for mesh ++ IEEE80211_MESH_SCANNING, ++ IEEE80211_MESH_LINKED, ++//by amy for mesh ++ ++}; ++ ++#define DEFAULT_MAX_SCAN_AGE (15 * HZ) ++#define DEFAULT_FTS 2346 ++#define MAC_FMT "%02x:%02x:%02x:%02x:%02x:%02x" ++#define MAC_ARG(x) ((u8*)(x))[0],((u8*)(x))[1],((u8*)(x))[2],((u8*)(x))[3],((u8*)(x))[4],((u8*)(x))[5] ++ ++ ++#if (LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,11)) ++extern inline int is_multicast_ether_addr(const u8 *addr) ++{ ++ return ((addr[0] != 0xff) && (0x01 & addr[0])); ++} ++#endif ++ ++#if (LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,13)) ++extern inline int is_broadcast_ether_addr(const u8 *addr) ++{ ++ return ((addr[0] == 0xff) && (addr[1] == 0xff) && (addr[2] == 0xff) && \ ++ (addr[3] == 0xff) && (addr[4] == 0xff) && (addr[5] == 0xff)); ++} ++#endif ++ ++#define CFG_IEEE80211_RESERVE_FCS (1<<0) ++#define CFG_IEEE80211_COMPUTE_FCS (1<<1) ++ ++typedef struct tx_pending_t{ ++ int frag; ++ struct ieee80211_txb *txb; ++}tx_pending_t; ++ ++#ifdef _RTL8187_EXT_PATCH_ ++struct ieee80211_crypt_data_list{ ++ u8 used; ++ u8 mac_addr[ETH_ALEN]; //record mac_add ++ struct ieee80211_crypt_data *crypt[WEP_KEYS]; ++}__attribute__((packed)); ++ ++#endif ++ ++struct ieee80211_device { ++ struct net_device *dev; ++ ++ /* Bookkeeping structures */ ++ struct net_device_stats stats; ++ struct ieee80211_stats ieee_stats; ++ struct ieee80211_softmac_stats softmac_stats; ++ ++ /* Probe / Beacon management */ ++ struct list_head network_free_list; ++ struct list_head network_list; ++ struct ieee80211_network *networks; ++ int scans; ++ int scan_age; ++ ++ int iw_mode; /* operating mode (IW_MODE_*) */ ++#ifdef _RTL8187_EXT_PATCH_ ++ int iw_ext_mode; // if iw_mode == iw_ext_mode, do ext_patch_**(); ++#endif ++ ++ spinlock_t lock; ++ spinlock_t wpax_suitlist_lock; ++ ++ int tx_headroom; /* Set to size of any additional room needed at front ++ * of allocated Tx SKBs */ ++ u32 config; ++ ++ /* WEP and other encryption related settings at the device level */ ++ int open_wep; /* Set to 1 to allow unencrypted frames */ ++ ++ int reset_on_keychange; /* Set to 1 if the HW needs to be reset on ++ * WEP key changes */ ++ ++ /* If the host performs {en,de}cryption, then set to 1 */ ++ int host_encrypt; ++ int host_decrypt; ++ int ieee802_1x; /* is IEEE 802.1X used */ ++ ++ /* WPA data */ ++ int wpa_enabled; ++ int drop_unencrypted; ++ int tkip_countermeasures; ++ int privacy_invoked; ++ size_t wpa_ie_len; ++ u8 *wpa_ie; ++ ++//#ifdef JOHN_TKIP ++ u8 ap_mac_addr[6]; ++ u16 pairwise_key_type; ++ u16 broadcast_key_type; ++//#endif ++ struct list_head crypt_deinit_list; ++#ifdef _RTL8187_EXT_PATCH_ ++ struct ieee80211_crypt_data_list* cryptlist[MAX_MP]; ++#else ++ struct ieee80211_crypt_data *crypt[WEP_KEYS]; ++#endif ++ int tx_keyidx; /* default TX key index (crypt[tx_keyidx]) */ ++ struct timer_list crypt_deinit_timer; ++ ++ int bcrx_sta_key; /* use individual keys to override default keys even ++ * with RX of broad/multicast frames */ ++ ++ /* Fragmentation structures */ ++ // each streaming contain a entry ++ struct ieee80211_frag_entry frag_cache[17][IEEE80211_FRAG_CACHE_LEN]; ++ unsigned int frag_next_idx[17]; ++ u16 fts; /* Fragmentation Threshold */ ++ ++ /* This stores infos for the current network. ++ * Either the network we are associated in INFRASTRUCTURE ++ * or the network that we are creating in MASTER mode. ++ * ad-hoc is a mixture ;-). ++ * Note that in infrastructure mode, even when not associated, ++ * fields bssid and essid may be valid (if wpa_set and essid_set ++ * are true) as thy carry the value set by the user via iwconfig ++ */ ++ struct ieee80211_network current_network; ++ ++ ++ enum ieee80211_state state; ++ ++ int short_slot; ++ int mode; /* A, B, G */ ++ int modulation; /* CCK, OFDM */ ++ int freq_band; /* 2.4Ghz, 5.2Ghz, Mixed */ ++ int abg_true; /* ABG flag */ ++ ++ /* used for forcing the ibss workqueue to terminate ++ * without wait for the syncro scan to terminate ++ */ ++ short sync_scan_hurryup; ++ ++#ifdef ENABLE_DOT11D ++ void * pDot11dInfo; ++ bool bGlobalDomain; ++ bool bWorldWide13;//lzm add 20081205 ++ ++ // For Liteon Ch12~13 passive scan ++ u8 MinPassiveChnlNum; ++ u8 IbssStartChnl; ++#else ++ /* map of allowed channels. 0 is dummy */ ++ // FIXME: remeber to default to a basic channel plan depending of the PHY type ++ int channel_map[MAX_CHANNEL_NUMBER+1]; ++#endif ++ ++ int rate; /* current rate */ ++ int basic_rate; ++ //FIXME: pleace callback, see if redundant with softmac_features ++ short active_scan; ++ ++#ifdef _RTL8187_EXT_PATCH_ ++// short ch_lock; ++ short meshScanMode; ++#endif ++ /* this contains flags for selectively enable softmac support */ ++ u16 softmac_features; ++ ++ /* if the sequence control field is not filled by HW */ ++ u16 seq_ctrl[5]; ++ ++ /* association procedure transaction sequence number */ ++ u16 associate_seq; ++ ++ /* AID for RTXed association responses */ ++ u16 assoc_id; ++ ++ /* power save mode related*/ ++ short ps; ++ short sta_sleep; ++ int ps_timeout; ++ struct tasklet_struct ps_task; ++ u32 ps_th; ++ u32 ps_tl; ++ ++ short raw_tx; ++ /* used if IEEE_SOFTMAC_TX_QUEUE is set */ ++ short queue_stop; ++ short scanning; ++ short scan_watchdog;//lzm add 081215 for roaming ++ short proto_started; ++ ++ struct semaphore wx_sem; ++ struct semaphore scan_sem; ++ struct semaphore ips_sem; ++ spinlock_t mgmt_tx_lock; ++ spinlock_t beacon_lock; ++ spinlock_t beaconflag_lock; ++ short beacon_txing; ++ ++ short wap_set; ++ short ssid_set; ++ ++ u8 wpax_type_set; //{added by David, 2006.9.28} ++ u32 wpax_type_notify; //{added by David, 2006.9.26} ++ ++ /* QoS related flag */ ++ char init_wmmparam_flag; ++ ++ /* for discarding duplicated packets in IBSS */ ++ struct list_head ibss_mac_hash[IEEE_IBSS_MAC_HASH_SIZE]; ++ ++ /* for discarding duplicated packets in Mesh */ //added by david 2008.2.28/ ++ struct list_head mesh_mac_hash[IEEE_MESH_MAC_HASH_SIZE]; ++ ++ /* for discarding duplicated packets in BSS */ ++ u16 last_rxseq_num[17]; /* rx seq previous per-tid */ ++ u16 last_rxfrag_num[17];/* tx frag previous per-tid */ ++ unsigned long last_packet_time[17]; ++ ++ /* for PS mode */ ++ unsigned long last_rx_ps_time; ++ ++ /* used if IEEE_SOFTMAC_SINGLE_QUEUE is set */ ++ struct sk_buff *mgmt_queue_ring[MGMT_QUEUE_NUM]; ++ int mgmt_queue_head; ++ int mgmt_queue_tail; ++//by amy for ps ++ bool bInactivePs; ++ bool actscanning; ++ u16 ListenInterval; ++ u32 NumRxData; ++ unsigned long NumRxDataInPeriod; //YJ,add,080828 ++ unsigned long NumRxBcnInPeriod; //YJ,add,080828 ++//by amy for ps ++ short meshid_set; ++ /* used if IEEE_SOFTMAC_TX_QUEUE is set */ ++ struct tx_pending_t tx_pending; ++ ++ /* used if IEEE_SOFTMAC_ASSOCIATE is set */ ++ struct timer_list associate_timer; ++ ++ /* used if IEEE_SOFTMAC_BEACONS is set */ ++ struct timer_list beacon_timer; ++#if LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0) ++ struct work_struct associate_complete_wq; ++// struct work_struct associate_retry_wq; ++// struct work_struct start_ibss_wq; ++ struct work_struct associate_procedure_wq; ++ struct work_struct ips_leave_wq; //YJ,add,081230,for IPS ++ bool bHwRadioOff;//by lizhaoming ++#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,20) ++ struct delayed_work softmac_scan_wq; ++ struct delayed_work start_ibss_wq; ++ struct delayed_work associate_retry_wq; ++//by amy for rate adaptive ++ struct delayed_work rate_adapter_wq; ++//by amy for rate adaptive ++ struct delayed_work watch_dog_wq; ++ struct delayed_work hw_dig_wq; ++ struct delayed_work tx_pw_wq; ++ ++#ifdef SW_ANTE_DIVERSITY ++ struct delayed_work SwAntennaWorkItem; ++#endif ++ ++#else ++ struct work_struct softmac_scan_wq; ++ struct work_struct start_ibss_wq; ++ struct work_struct associate_retry_wq; ++//by amy for rate adaptive ++ struct work_struct rate_adapter_wq; ++//by amy for rate adaptive ++ struct work_struct watch_dog_wq; ++ struct work_struct hw_dig_wq; ++ struct work_struct tx_pw_wq; ++ ++#ifdef SW_ANTE_DIVERSITY ++ struct work_struct SwAntennaWorkItem; ++#endif ++ ++#endif ++ ++//struct work_struct softmac_scan_wq; ++ struct work_struct wx_sync_scan_wq; ++ struct work_struct wmm_param_update_wq; ++#ifdef _RTL8187_EXT_PATCH_ ++ struct work_struct ext_stop_scan_wq; ++ struct work_struct ext_send_beacon_wq; ++#endif ++ struct workqueue_struct *wq; ++#else ++ /* used for periodly scan */ ++ struct timer_list scan_timer; ++ ++ struct tq_struct associate_complete_wq; ++ struct tq_struct associate_retry_wq; ++ struct tq_struct start_ibss_wq; ++ struct tq_struct associate_procedure_wq; ++ struct tq_struct ips_leave_wq; //YJ,add,081230,for IPS ++ struct tq_struct softmac_scan_wq; ++ struct tq_struct wx_sync_scan_wq; ++ struct tq_struct wmm_param_update_wq; ++#ifdef _RTL8187_EXT_PATCH_ ++ struct tq_struct ext_stop_scan_wq; ++ struct tq_struct ext_send_beacon_wq; ++#endif ++#endif ++ ++ /* Callback functions */ ++ void (*set_security)(struct net_device *dev, ++ struct ieee80211_security *sec); ++ ++ /* Used to TX data frame by using txb structs. ++ * this is not used if in the softmac_features ++ * is set the flag IEEE_SOFTMAC_TX_QUEUE ++ */ ++ int (*hard_start_xmit)(struct ieee80211_txb *txb, ++ struct net_device *dev); ++ ++ int (*reset_port)(struct net_device *dev); ++ ++ /* Softmac-generated frames (mamagement) are TXed via this ++ * callback if the flag IEEE_SOFTMAC_SINGLE_QUEUE is ++ * not set. As some cards may have different HW queues that ++ * one might want to use for data and management frames ++ * the option to have two callbacks might be useful. ++ * This fucntion can't sleep. ++ */ ++ int (*softmac_hard_start_xmit)(struct sk_buff *skb, ++ struct net_device *dev); ++ ++ /* used instead of hard_start_xmit (not softmac_hard_start_xmit) ++ * if the IEEE_SOFTMAC_TX_QUEUE feature is used to TX data ++ * frames. I the option IEEE_SOFTMAC_SINGLE_QUEUE is also set ++ * then also management frames are sent via this callback. ++ * This function can't sleep. ++ */ ++ void (*softmac_data_hard_start_xmit)(struct sk_buff *skb, ++ struct net_device *dev,int rate); ++ ++ /* stops the HW queue for DATA frames. Useful to avoid ++ * waste time to TX data frame when we are reassociating ++ * This function can sleep. ++ */ ++ void (*data_hard_stop)(struct net_device *dev); ++ ++ /* OK this is complementar to data_poll_hard_stop */ ++ void (*data_hard_resume)(struct net_device *dev); ++ ++ /* ask to the driver to retune the radio . ++ * This function can sleep. the driver should ensure ++ * the radio has been swithced before return. ++ */ ++ void (*set_chan)(struct net_device *dev,short ch); ++ ++ /* These are not used if the ieee stack takes care of ++ * scanning (IEEE_SOFTMAC_SCAN feature set). ++ * In this case only the set_chan is used. ++ * ++ * The syncro version is similar to the start_scan but ++ * does not return until all channels has been scanned. ++ * this is called in user context and should sleep, ++ * it is called in a work_queue when swithcing to ad-hoc mode ++ * or in behalf of iwlist scan when the card is associated ++ * and root user ask for a scan. ++ * the fucntion stop_scan should stop both the syncro and ++ * background scanning and can sleep. ++ * The fucntion start_scan should initiate the background ++ * scanning and can't sleep. ++ */ ++ void (*scan_syncro)(struct net_device *dev); ++ void (*start_scan)(struct net_device *dev); ++ void (*stop_scan)(struct net_device *dev); ++ ++ /* indicate the driver that the link state is changed ++ * for example it may indicate the card is associated now. ++ * Driver might be interested in this to apply RX filter ++ * rules or simply light the LINK led ++ */ ++ void (*link_change)(struct net_device *dev); ++ ++ /* these two function indicates to the HW when to start ++ * and stop to send beacons. This is used when the ++ * IEEE_SOFTMAC_BEACONS is not set. For now the ++ * stop_send_bacons is NOT guaranteed to be called only ++ * after start_send_beacons. ++ */ ++ void (*start_send_beacons) (struct net_device *dev); ++ void (*stop_send_beacons) (struct net_device *dev); ++ ++ /* power save mode related */ ++ void (*sta_wake_up) (struct net_device *dev); ++ void (*ps_request_tx_ack) (struct net_device *dev); ++ void (*enter_sleep_state) (struct net_device *dev, u32 th, u32 tl); ++ short (*ps_is_queue_empty) (struct net_device *dev); ++ ++//by lizhaoming for LED 2008.6.23 ++#ifdef LED ++ void (*ieee80211_led_contorl) (struct net_device *dev, LED_CTL_MODE LedAction); ++#endif ++#ifdef CONFIG_IPS ++ void (*ieee80211_ips_leave) (struct net_device *dev); ++#endif ++ /* QoS related */ ++ //void (*wmm_param_update) (struct net_device *dev, u8 *ac_param); ++ //void (*wmm_param_update) (struct ieee80211_device *ieee); ++ ++ ++#ifdef _RTL8187_EXT_PATCH_ ++ ++ /// ieee80211_softmac.c ++ int (*ext_patch_ieee80211_start_protocol) (struct ieee80211_device *ieee); // start special mode ++ ++ short (*ext_patch_ieee80211_probe_req_1) (struct ieee80211_device *ieee); // return = 0: no more phases, >0: another phase ++ u8* (*ext_patch_ieee80211_probe_req_2) (struct ieee80211_device *ieee, struct sk_buff *skb, u8 *tag); // return tag ++ ++ void (*ext_patch_ieee80211_stop_protocol) (struct ieee80211_device *ieee); // stop timer ++ ++ void (*ext_patch_ieee80211_association_req_1) (struct ieee80211_assoc_request_frame *hdr); ++ u8* (*ext_patch_ieee80211_association_req_2) (struct ieee80211_device *ieee, struct ieee80211_network *pstat, struct sk_buff *skb); ++ ++ int (*ext_patch_ieee80211_rx_frame_softmac_on_assoc_req) (struct ieee80211_device *ieee, struct sk_buff *skb); ++ int (*ext_patch_ieee80211_rx_frame_softmac_on_assoc_rsp) (struct ieee80211_device *ieee, struct sk_buff *skb); ++ ++ void (*ext_patch_ieee80211_assoc_resp_by_net_1) (struct ieee80211_assoc_response_frame *assoc); ++ u8* (*ext_patch_ieee80211_assoc_resp_by_net_2) (struct ieee80211_device *ieee, struct ieee80211_network *pstat, int pkt_type, struct sk_buff *skb); ++ ++ int (*ext_patch_ieee80211_ext_stop_scan_wq_set_channel) (struct ieee80211_device *ieee); ++ ++ int (*ext_patch_ieee80211_softmac_xmit_get_rate) (struct ieee80211_device *ieee, struct sk_buff *skb); ++ ++ int (*ext_patch_ieee80211_rx_frame_softmac_on_auth)(struct ieee80211_device *ieee, struct sk_buff *skb, struct ieee80211_rx_stats *rx_stats); ++ int (*ext_patch_ieee80211_rx_frame_softmac_on_deauth)(struct ieee80211_device *ieee, struct sk_buff *skb, struct ieee80211_rx_stats *rx_stats); ++//by amy for mesh ++ void (*ext_patch_ieee80211_start_mesh)(struct ieee80211_device *ieee); ++//by amy for mesh ++ // ieee80211_rx.c ++ // rz ++ void (*ext_patch_ieee80211_rx_mgt_on_probe_req) ( struct ieee80211_device *ieee, struct ieee80211_probe_request *beacon, struct ieee80211_rx_stats *stats); ++ unsigned int(*ext_patch_ieee80211_process_probe_response_1)(struct ieee80211_device *ieee, struct ieee80211_probe_response *beacon, struct ieee80211_rx_stats *stats); ++ ++ void (*ext_patch_ieee80211_rx_mgt_update_expire) ( struct ieee80211_device *ieee, struct sk_buff *skb); ++ struct sk_buff* (*ext_patch_get_beacon_get_probersp)(struct ieee80211_device *ieee, u8 *dest, struct ieee80211_network *net); ++ ++ // success(return 0) is responsible to free skb ++ int (*ext_patch_ieee80211_rx_on_rx) (struct ieee80211_device *ieee, struct sk_buff *skb, struct ieee80211_rx_stats *rx_stats, u16 type, u16 stype); ++ ++ int (*ext_patch_ieee80211_rx_frame_get_hdrlen) (struct ieee80211_device *ieee, struct sk_buff *skb); ++ ++ // Check whether or not accept the incoming frame. return 0: not accept, >0: accept ++ int (*ext_patch_ieee80211_rx_is_valid_framectl) (struct ieee80211_device *ieee, u16 fc, u16 type, u16 stype); ++ ++ // return > 0 is success. 0 when failed ++ // success(return >0) is responsible to free skb ++ int (*ext_patch_ieee80211_rx_process_dataframe) (struct ieee80211_device *ieee, struct sk_buff *skb, struct ieee80211_rx_stats *rx_stats); ++ ++ /* added by david for setting acl dynamically */ ++ u8 (*ext_patch_ieee80211_acl_query) (struct ieee80211_device *ieee, u8 *sa); ++ ++ // int (*ext_patch_is_duplicate_packet) (struct ieee80211_device *ieee, struct ieee80211_hdr *header, u16 type, u16 stype); ++ ++ // ieee80211_tx.c ++ ++ // locked by ieee->lock. Call ieee80211_softmac_xmit afterward ++ struct ieee80211_txb* (*ext_patch_ieee80211_xmit) (struct sk_buff *skb, struct net_device *dev); ++ ++ ++#endif // _RTL8187_EXT_PATCH_ ++ ++ /* This must be the last item so that it points to the data ++ * allocated beyond this structure by alloc_ieee80211 */ ++ u8 priv[0]; ++}; ++ ++#define IEEE_A (1<<0) ++#define IEEE_B (1<<1) ++#define IEEE_G (1<<2) ++#define IEEE_MODE_MASK (IEEE_A|IEEE_B|IEEE_G) ++ ++/* Generate a 802.11 header */ ++ ++/* Uses the channel change callback directly ++ * instead of [start/stop] scan callbacks ++ */ ++#define IEEE_SOFTMAC_SCAN (1<<2) ++ ++/* Perform authentication and association handshake */ ++#define IEEE_SOFTMAC_ASSOCIATE (1<<3) ++ ++/* Generate probe requests */ ++#define IEEE_SOFTMAC_PROBERQ (1<<4) ++ ++/* Generate respones to probe requests */ ++#define IEEE_SOFTMAC_PROBERS (1<<5) ++ ++/* The ieee802.11 stack will manages the netif queue ++ * wake/stop for the driver, taking care of 802.11 ++ * fragmentation. See softmac.c for details. */ ++#define IEEE_SOFTMAC_TX_QUEUE (1<<7) ++ ++/* Uses only the softmac_data_hard_start_xmit ++ * even for TX management frames. ++ */ ++#define IEEE_SOFTMAC_SINGLE_QUEUE (1<<8) ++ ++/* Generate beacons. The stack will enqueue beacons ++ * to the card ++ */ ++#define IEEE_SOFTMAC_BEACONS (1<<6) ++#ifdef _RTL8187_EXT_PATCH_ ++extern inline int ieee80211_find_MP(struct ieee80211_device* ieee, const u8* addr, u8 set) ++{ ++ int i=0; ++ for (i=1; i<MAX_MP; i++) ++ { ++ if ((ieee->cryptlist[i]->used == 0)&&set) ++ {//entry is empty ++ memcpy(ieee->cryptlist[i]->mac_addr, addr, ETH_ALEN); ++ ieee->cryptlist[i]->used = 1; ++ return i; ++ } ++ else if (0 == memcmp(ieee->cryptlist[i]->mac_addr, addr, ETH_ALEN)) //find matched entry ++ { ++ return i; ++ } ++ } ++ return -1; ++} ++#endif ++ ++ ++ ++static inline void *ieee80211_priv(struct net_device *dev) ++{ ++#if LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0) ++ return ((struct ieee80211_device *)netdev_priv(dev))->priv; ++#else ++ return ((struct ieee80211_device *)dev->priv)->priv; ++#endif ++} ++ ++extern inline int ieee80211_is_empty_essid(const char *essid, int essid_len) ++{ ++ /* Single white space is for Linksys APs */ ++ if (essid_len == 1 && essid[0] == ' ') ++ return 1; ++ ++ /* Otherwise, if the entire essid is 0, we assume it is hidden */ ++ while (essid_len) { ++ essid_len--; ++ if (essid[essid_len] != '\0') ++ return 0; ++ } ++ ++ return 1; ++} ++ ++extern inline int ieee80211_is_valid_mode(struct ieee80211_device *ieee, int mode) ++{ ++ /* ++ * It is possible for both access points and our device to support ++ * combinations of modes, so as long as there is one valid combination ++ * of ap/device supported modes, then return success ++ * ++ */ ++ if ((mode & IEEE_A) && ++ (ieee->modulation & IEEE80211_OFDM_MODULATION) && ++ (ieee->freq_band & IEEE80211_52GHZ_BAND)) ++ return 1; ++ ++ if ((mode & IEEE_G) && ++ (ieee->modulation & IEEE80211_OFDM_MODULATION) && ++ (ieee->freq_band & IEEE80211_24GHZ_BAND)) ++ return 1; ++ ++ if ((mode & IEEE_B) && ++ (ieee->modulation & IEEE80211_CCK_MODULATION) && ++ (ieee->freq_band & IEEE80211_24GHZ_BAND)) ++ return 1; ++ ++ return 0; ++} ++ ++extern inline int ieee80211_get_hdrlen(u16 fc) ++{ ++ int hdrlen = 24; ++ ++ switch (WLAN_FC_GET_TYPE(fc)) { ++ case IEEE80211_FTYPE_DATA: ++ if ((fc & IEEE80211_FCTL_FROMDS) && (fc & IEEE80211_FCTL_TODS)) ++ hdrlen = 30; /* Addr4 */ ++ if(IEEE80211_QOS_HAS_SEQ(fc)) ++ hdrlen += 2; /* QOS ctrl*/ ++ break; ++ case IEEE80211_FTYPE_CTL: ++ switch (WLAN_FC_GET_STYPE(fc)) { ++ case IEEE80211_STYPE_CTS: ++ case IEEE80211_STYPE_ACK: ++ hdrlen = 10; ++ break; ++ default: ++ hdrlen = 16; ++ break; ++ } ++ break; ++ } ++ ++ return hdrlen; ++} ++ ++ ++ ++/* ieee80211.c */ ++extern void free_ieee80211(struct net_device *dev); ++extern struct net_device *alloc_ieee80211(int sizeof_priv); ++ ++extern int ieee80211_set_encryption(struct ieee80211_device *ieee); ++ ++/* ieee80211_tx.c */ ++ ++extern int ieee80211_encrypt_fragment( ++ struct ieee80211_device *ieee, ++ struct sk_buff *frag, ++ int hdr_len); ++ ++extern int ieee80211_xmit(struct sk_buff *skb, ++ struct net_device *dev); ++extern void ieee80211_txb_free(struct ieee80211_txb *); ++ ++ ++/* ieee80211_rx.c */ ++extern int ieee80211_rx(struct ieee80211_device *ieee, struct sk_buff *skb, ++ struct ieee80211_rx_stats *rx_stats); ++extern void ieee80211_rx_mgt(struct ieee80211_device *ieee, ++ struct ieee80211_hdr *header, ++ struct ieee80211_rx_stats *stats); ++ ++/* ieee80211_wx.c */ ++extern int ieee80211_wx_get_scan(struct ieee80211_device *ieee, ++ struct iw_request_info *info, ++ union iwreq_data *wrqu, char *key); ++extern int ieee80211_wx_set_encode(struct ieee80211_device *ieee, ++ struct iw_request_info *info, ++ union iwreq_data *wrqu, char *key); ++extern int ieee80211_wx_get_encode(struct ieee80211_device *ieee, ++ struct iw_request_info *info, ++ union iwreq_data *wrqu, char *key); ++extern int ieee80211_wx_set_encode_ext(struct ieee80211_device *ieee, ++ struct iw_request_info *info, ++ union iwreq_data* wrqu, char *extra); ++int ieee80211_wx_set_auth(struct ieee80211_device *ieee, ++ struct iw_request_info *info, ++ struct iw_param *data, char *extra); ++int ieee80211_wx_set_mlme(struct ieee80211_device *ieee, ++ struct iw_request_info *info, ++ union iwreq_data *wrqu, char *extra); ++ ++int ieee80211_wx_set_gen_ie(struct ieee80211_device *ieee, u8 *ie, size_t len); ++/* ieee80211_softmac.c */ ++extern short ieee80211_is_54g(struct ieee80211_network net); ++extern short ieee80211_is_shortslot(struct ieee80211_network net); ++extern int ieee80211_rx_frame_softmac(struct ieee80211_device *ieee, struct sk_buff *skb, ++ struct ieee80211_rx_stats *rx_stats, u16 type, ++ u16 stype); ++extern void ieee80211_softmac_new_net(struct ieee80211_device *ieee, struct ieee80211_network *net); ++ ++extern void ieee80211_softmac_xmit(struct ieee80211_txb *txb, struct ieee80211_device *ieee); ++extern void ieee80211_softmac_check_all_nets(struct ieee80211_device *ieee); ++extern void ieee80211_start_bss(struct ieee80211_device *ieee); ++extern void ieee80211_start_master_bss(struct ieee80211_device *ieee); ++extern void ieee80211_start_ibss(struct ieee80211_device *ieee); ++extern void ieee80211_softmac_init(struct ieee80211_device *ieee); ++extern void ieee80211_softmac_free(struct ieee80211_device *ieee); ++extern void ieee80211_associate_abort(struct ieee80211_device *ieee); ++extern void ieee80211_disassociate(struct ieee80211_device *ieee); ++extern void ieee80211_stop_scan(struct ieee80211_device *ieee); ++extern void ieee80211_start_scan_syncro(struct ieee80211_device *ieee); ++extern void ieee80211_check_all_nets(struct ieee80211_device *ieee); ++extern void ieee80211_start_protocol(struct ieee80211_device *ieee); ++extern void ieee80211_stop_protocol(struct ieee80211_device *ieee); ++extern void ieee80211_softmac_start_protocol(struct ieee80211_device *ieee); ++extern void ieee80211_softmac_stop_protocol(struct ieee80211_device *ieee); ++extern void ieee80211_reset_queue(struct ieee80211_device *ieee); ++extern void ieee80211_wake_queue(struct ieee80211_device *ieee); ++extern void ieee80211_stop_queue(struct ieee80211_device *ieee); ++extern struct sk_buff *ieee80211_get_beacon(struct ieee80211_device *ieee); ++extern void ieee80211_start_send_beacons(struct ieee80211_device *ieee); ++extern void ieee80211_stop_send_beacons(struct ieee80211_device *ieee); ++extern int ieee80211_wpa_supplicant_ioctl(struct ieee80211_device *ieee, struct iw_point *p); ++extern void notify_wx_assoc_event(struct ieee80211_device *ieee); ++extern void ieee80211_ps_tx_ack(struct ieee80211_device *ieee, short success); ++extern void ieee80211_start_scan(struct ieee80211_device *ieee); ++ ++#ifdef _RTL8187_EXT_PATCH_ ++extern void ieee80211_rx_auth_rq(struct ieee80211_device *ieee, struct sk_buff *skb); ++extern void ieee80211_ext_issue_assoc_req(struct ieee80211_device *ieee, struct ieee80211_network *pstat); ++extern void ieee80211_associate_step1(struct ieee80211_device *ieee); ++extern void ieee80211_ext_issue_disassoc(struct ieee80211_device *ieee, struct ieee80211_network *pstat, int reason, unsigned char extReason); ++extern void ieee80211_ext_issue_assoc_rsp(struct ieee80211_device *ieee, u8 *dest, unsigned short status, struct ieee80211_network *pstat, int pkt_type); ++extern void softmac_mgmt_xmit(struct sk_buff *skb, struct ieee80211_device *ieee); ++extern struct sk_buff* ieee80211_ext_probe_resp_by_net(struct ieee80211_device *ieee, u8 *dest, struct ieee80211_network *net); ++extern int ieee80211_network_init(struct ieee80211_device *ieee, struct ieee80211_probe_response *beacon, struct ieee80211_network *network, struct ieee80211_rx_stats *stats); ++extern struct ieee80211_txb *ieee80211_alloc_txb(int nr_frags, int txb_size, int gfp_mask); ++extern void ieee80211_ext_send_11s_beacon(struct ieee80211_device *ieee); ++extern struct ieee80211_txb *ieee80211_ext_alloc_txb(struct sk_buff *skb, struct net_device *dev, struct ieee80211_hdr_3addr *header, int hdr_len, u8 isQoS, u16 *pQOS_ctl, int isEncrypt, struct ieee80211_crypt_data* crypt); ++extern struct ieee80211_txb *ieee80211_ext_reuse_txb(struct sk_buff *skb, struct net_device *dev, struct ieee80211_hdr_3addr *header, int hdr_len, u8 isQoS, u16 *pQOS_ctl, int isEncrypt, struct ieee80211_crypt_data* crypt); ++extern int ieee_ext_skb_p80211_to_ether(struct sk_buff *skb, int hdrlen, u8 *dst, u8 *src); ++#endif ++ ++/* ieee80211_crypt_ccmp&tkip&wep.c */ ++extern void ieee80211_tkip_null(void); ++extern void ieee80211_wep_null(void); ++extern void ieee80211_ccmp_null(void); ++/* ieee80211_softmac_wx.c */ ++ ++extern int ieee80211_wx_get_wap(struct ieee80211_device *ieee, ++ struct iw_request_info *info, ++ union iwreq_data *wrqu, char *ext); ++ ++extern int ieee80211_wx_set_wap(struct ieee80211_device *ieee, ++ struct iw_request_info *info, ++ union iwreq_data *awrq, ++ char *extra); ++ ++extern int ieee80211_wx_get_essid(struct ieee80211_device *ieee, struct iw_request_info *a,union iwreq_data *wrqu,char *b); ++ ++extern int ieee80211_wx_set_rate(struct ieee80211_device *ieee, ++ struct iw_request_info *info, ++ union iwreq_data *wrqu, char *extra); ++ ++extern int ieee80211_wx_get_rate(struct ieee80211_device *ieee, ++ struct iw_request_info *info, ++ union iwreq_data *wrqu, char *extra); ++ ++extern int ieee80211_wx_set_mode(struct ieee80211_device *ieee, struct iw_request_info *a, ++ union iwreq_data *wrqu, char *b); ++ ++extern int ieee80211_wx_set_scan(struct ieee80211_device *ieee, struct iw_request_info *a, ++ union iwreq_data *wrqu, char *b); ++ ++extern int ieee80211_wx_set_essid(struct ieee80211_device *ieee, ++ struct iw_request_info *a, ++ union iwreq_data *wrqu, char *extra); ++ ++extern int ieee80211_wx_get_mode(struct ieee80211_device *ieee, struct iw_request_info *a, ++ union iwreq_data *wrqu, char *b); ++ ++extern int ieee80211_wx_set_freq(struct ieee80211_device *ieee, struct iw_request_info *a, ++ union iwreq_data *wrqu, char *b); ++ ++extern int ieee80211_wx_get_freq(struct ieee80211_device *ieee, struct iw_request_info *a, ++ union iwreq_data *wrqu, char *b); ++ ++//extern void ieee80211_wx_sync_scan_wq(struct ieee80211_device *ieee); ++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,20)) ++extern void ieee80211_wx_sync_scan_wq(struct work_struct *work); ++#else ++ extern void ieee80211_wx_sync_scan_wq(struct ieee80211_device *ieee); ++#endif ++extern int ieee80211_wx_set_rawtx(struct ieee80211_device *ieee, ++ struct iw_request_info *info, ++ union iwreq_data *wrqu, char *extra); ++ ++extern int ieee80211_wx_get_name(struct ieee80211_device *ieee, ++ struct iw_request_info *info, ++ union iwreq_data *wrqu, char *extra); ++ ++extern int ieee80211_wx_set_power(struct ieee80211_device *ieee, ++ struct iw_request_info *info, ++ union iwreq_data *wrqu, char *extra); ++ ++extern int ieee80211_wx_get_power(struct ieee80211_device *ieee, ++ struct iw_request_info *info, ++ union iwreq_data *wrqu, char *extra); ++ ++extern const long ieee80211_wlan_frequencies[]; ++ ++extern inline void ieee80211_increment_scans(struct ieee80211_device *ieee) ++{ ++ ieee->scans++; ++} ++ ++extern inline int ieee80211_get_scans(struct ieee80211_device *ieee) ++{ ++ return ieee->scans; ++} ++ ++static inline const char *escape_essid(const char *essid, u8 essid_len) { ++ static char escaped[IW_ESSID_MAX_SIZE * 2 + 1]; ++ const char *s = essid; ++ char *d = escaped; ++ ++ if (ieee80211_is_empty_essid(essid, essid_len)) { ++ memcpy(escaped, "<hidden>", sizeof("<hidden>")); ++ return escaped; ++ } ++ ++ essid_len = min(essid_len, (u8)IW_ESSID_MAX_SIZE); ++ while (essid_len--) { ++ if (*s == '\0') { ++ *d++ = '\\'; ++ *d++ = '0'; ++ s++; ++ } else { ++ *d++ = *s++; ++ } ++ } ++ *d = '\0'; ++ return escaped; ++} ++#endif /* IEEE80211_H */ +diff -Nur linux-2.6.33/drivers/net/wireless/rtl8187b/ieee80211/ieee80211_module.c linux-lemote/drivers/net/wireless/rtl8187b/ieee80211/ieee80211_module.c +--- linux-2.6.33/drivers/net/wireless/rtl8187b/ieee80211/ieee80211_module.c 1970-01-01 01:00:00.000000000 +0100 ++++ linux-lemote/drivers/net/wireless/rtl8187b/ieee80211/ieee80211_module.c 2010-03-06 16:43:22.000000000 +0100 +@@ -0,0 +1,385 @@ ++/******************************************************************************* ++ ++ Copyright(c) 2004 Intel Corporation. All rights reserved. ++ ++ Portions of this file are based on the WEP enablement code provided by the ++ Host AP project hostap-drivers v0.1.3 ++ Copyright (c) 2001-2002, SSH Communications Security Corp and Jouni Malinen ++ <jkmaline@cc.hut.fi> ++ Copyright (c) 2002-2003, Jouni Malinen <jkmaline@cc.hut.fi> ++ ++ This program is free software; you can redistribute it and/or modify it ++ under the terms of version 2 of the GNU General Public License as ++ published by the Free Software Foundation. ++ ++ 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. ++ ++ The full GNU General Public License is included in this distribution in the ++ file called LICENSE. ++ ++ Contact Information: ++ James P. Ketrenos <ipw2100-admin@linux.intel.com> ++ Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 ++ ++*******************************************************************************/ ++ ++#include <linux/compiler.h> ++//#include <linux/config.h> ++#include <linux/errno.h> ++#include <linux/if_arp.h> ++#include <linux/in6.h> ++#include <linux/in.h> ++#include <linux/ip.h> ++#include <linux/kernel.h> ++#include <linux/module.h> ++#include <linux/netdevice.h> ++#include <linux/pci.h> ++#include <linux/proc_fs.h> ++#include <linux/skbuff.h> ++#include <linux/slab.h> ++#include <linux/tcp.h> ++#include <linux/types.h> ++#include <linux/version.h> ++#include <linux/wireless.h> ++#include <linux/etherdevice.h> ++#include <asm/uaccess.h> ++#include <net/arp.h> ++ ++#include "ieee80211.h" ++ ++MODULE_DESCRIPTION("802.11 data/management/control stack"); ++MODULE_AUTHOR("Copyright (C) 2004 Intel Corporation <jketreno@linux.intel.com>"); ++MODULE_LICENSE("GPL"); ++ ++#define DRV_NAME "ieee80211" ++ ++static inline int ieee80211_networks_allocate(struct ieee80211_device *ieee) ++{ ++ if (ieee->networks) ++ return 0; ++ ++ ieee->networks = kmalloc( ++ MAX_NETWORK_COUNT * sizeof(struct ieee80211_network), ++ GFP_KERNEL); ++ if (!ieee->networks) { ++ printk(KERN_WARNING "%s: Out of memory allocating beacons\n", ++ ieee->dev->name); ++ return -ENOMEM; ++ } ++ ++ memset(ieee->networks, 0, ++ MAX_NETWORK_COUNT * sizeof(struct ieee80211_network)); ++ ++ return 0; ++} ++ ++static inline void ieee80211_networks_free(struct ieee80211_device *ieee) ++{ ++ if (!ieee->networks) ++ return; ++ kfree(ieee->networks); ++ ieee->networks = NULL; ++} ++ ++static inline void ieee80211_networks_initialize(struct ieee80211_device *ieee) ++{ ++ int i; ++ ++ INIT_LIST_HEAD(&ieee->network_free_list); ++ INIT_LIST_HEAD(&ieee->network_list); ++ for (i = 0; i < MAX_NETWORK_COUNT; i++) ++ list_add_tail(&ieee->networks[i].list, &ieee->network_free_list); ++} ++ ++ ++struct net_device *alloc_ieee80211(int sizeof_priv) ++{ ++ struct ieee80211_device *ieee; ++ struct net_device *dev; ++ int i,err; ++ ++ IEEE80211_DEBUG_INFO("Initializing...\n"); ++ ++ dev = alloc_etherdev(sizeof(struct ieee80211_device) + sizeof_priv); ++ if (!dev) { ++ IEEE80211_ERROR("Unable to network device.\n"); ++ goto failed; ++ } ++ ++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0)) ++ ieee = netdev_priv(dev); ++#else ++ ieee = (struct ieee80211_device *)dev->priv; ++#endif ++ ++ ieee->dev = dev; ++ ++ err = ieee80211_networks_allocate(ieee); ++ if (err) { ++ IEEE80211_ERROR("Unable to allocate beacon storage: %d\n", ++ err); ++ goto failed; ++ } ++ ieee80211_networks_initialize(ieee); ++ ++ /* Default fragmentation threshold is maximum payload size */ ++ ieee->fts = DEFAULT_FTS; ++ ieee->scan_age = DEFAULT_MAX_SCAN_AGE; ++ ieee->open_wep = 1; ++ ++ /* Default to enabling full open WEP with host based encrypt/decrypt */ ++ ieee->host_encrypt = 1; ++ ieee->host_decrypt = 1; ++ ieee->ieee802_1x = 1; /* Default to supporting 802.1x */ ++ ++ INIT_LIST_HEAD(&ieee->crypt_deinit_list); ++ init_timer(&ieee->crypt_deinit_timer); ++ ieee->crypt_deinit_timer.data = (unsigned long)ieee; ++ ieee->crypt_deinit_timer.function = ieee80211_crypt_deinit_handler; ++ ++ spin_lock_init(&ieee->lock); ++ spin_lock_init(&ieee->wpax_suitlist_lock); ++ ++ ieee->wpax_type_set = 0; ++ ieee->wpa_enabled = 0; ++ ieee->tkip_countermeasures = 0; ++ ieee->drop_unencrypted = 0; ++ ieee->privacy_invoked = 0; ++ ieee->ieee802_1x = 1; ++ ieee->raw_tx = 0; ++#ifdef _RTL8187_EXT_PATCH_ ++ for (i=0; i<MAX_MP; i++) ++ { ++ ieee->cryptlist[i] = (struct ieee80211_crypt_data_list*) kmalloc(sizeof(struct ieee80211_crypt_data_list), GFP_KERNEL); ++ if (NULL == ieee->cryptlist[i]) ++ { ++ printk("error kmalloc cryptlist\n"); ++ goto failed; ++ } ++ memset(ieee->cryptlist[i], 0, sizeof(struct ieee80211_crypt_data_list)); ++ ++ } ++#endif ++ ieee80211_softmac_init(ieee); ++ ++ for (i = 0; i < IEEE_IBSS_MAC_HASH_SIZE; i++) ++ INIT_LIST_HEAD(&ieee->ibss_mac_hash[i]); ++ ++ for (i = 0; i < IEEE_MESH_MAC_HASH_SIZE; i++) ++ INIT_LIST_HEAD(&ieee->mesh_mac_hash[i]); ++ ++ for (i = 0; i < 17; i++) { ++ ieee->last_rxseq_num[i] = -1; ++ ieee->last_rxfrag_num[i] = -1; ++ ieee->last_packet_time[i] = 0; ++ } ++#if 1 //added these to autoload encryption module. WB ++ ieee80211_tkip_null(); ++ ieee80211_wep_null(); ++ ieee80211_ccmp_null(); ++#endif ++ return dev; ++ ++ failed: ++#ifdef _RTL8187_EXT_PATCH_ ++ for (i=0; i<MAX_MP; i++) ++ { ++ if (ieee->cryptlist[i]==NULL){ ++ continue; ++ } ++ kfree(ieee->cryptlist[i]); ++ ieee->cryptlist[i] = NULL; ++ ++ } ++#endif ++ if (dev) ++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0)) ++ free_netdev(dev); ++#else ++ kfree(dev); ++#endif ++ return NULL; ++} ++ ++ ++void free_ieee80211(struct net_device *dev) ++{ ++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0)) ++ struct ieee80211_device *ieee = netdev_priv(dev); ++#else ++ struct ieee80211_device *ieee = (struct ieee80211_device *)dev->priv; ++#endif ++ int i;//,j; ++ struct list_head *p, *q; ++ ++ ++ ieee80211_softmac_free(ieee); ++ del_timer_sync(&ieee->crypt_deinit_timer); ++ ieee80211_crypt_deinit_entries(ieee, 1); ++#if 1 ++ ieee80211_tkip_null(); ++ ieee80211_wep_null(); ++ ieee80211_ccmp_null(); ++#endif ++ for (i = 0; i < WEP_KEYS; i++) { ++#ifdef _RTL8187_EXT_PATCH_ ++{ ++ // int j; ++ for (j=0;j<MAX_MP; j++){ ++ if (ieee->cryptlist[j] == NULL) ++ continue; ++ struct ieee80211_crypt_data *crypt = ieee->cryptlist[j]->crypt[i]; ++#else ++ struct ieee80211_crypt_data *crypt = ieee->crypt[i]; ++#endif ++ if (crypt) { ++ if (crypt->ops) { ++ crypt->ops->deinit(crypt->priv); ++#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0) ++ module_put(crypt->ops->owner); ++#else ++ __MOD_DEC_USE_COUNT(crypt->ops->owner); ++#endif ++ } ++ kfree(crypt); ++#ifdef _RTL8187_EXT_PATCH_ ++ ieee->cryptlist[j]->crypt[i] = NULL; ++ //kfree(ieee->cryptlist[j]); ++ //ieee->cryptlist[j] = NULL; ++#else ++ ieee->crypt[i] = NULL; ++#endif ++ } ++#ifdef _RTL8187_EXT_PATCH_ ++ } ++ } ++#endif ++} ++#ifdef _RTL8187_EXT_PATCH_ ++for(j=0;j<MAX_MP;j++) ++ { ++ if (ieee->cryptlist[j]) ++ { ++ kfree(ieee->cryptlist[j]); ++ ieee->cryptlist[j] = NULL; ++ } ++ } ++ ++ for (i = 0; i < IEEE_MESH_MAC_HASH_SIZE; i++) { ++ list_for_each_safe(p, q, &ieee->mesh_mac_hash[i]) { ++ kfree(list_entry(p, struct ieee_mesh_seq, list)); ++ list_del(p); ++ } ++ } ++#endif ++ ieee80211_networks_free(ieee); ++ ++ for (i = 0; i < IEEE_IBSS_MAC_HASH_SIZE; i++) { ++ list_for_each_safe(p, q, &ieee->ibss_mac_hash[i]) { ++ kfree(list_entry(p, struct ieee_ibss_seq, list)); ++ list_del(p); ++ } ++ } ++ ++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0)) ++ free_netdev(dev); ++#else ++ kfree(dev); ++#endif ++} ++ ++#ifdef CONFIG_IEEE80211_DEBUG ++ ++static int debug = 0; ++u32 ieee80211_debug_level = 0; ++struct proc_dir_entry *ieee80211_proc = NULL; ++ ++static int show_debug_level(char *page, char **start, off_t offset, ++ int count, int *eof, void *data) ++{ ++ return snprintf(page, count, "0x%08X\n", ieee80211_debug_level); ++} ++ ++static int store_debug_level(struct file *file, const char *buffer, ++ unsigned long count, void *data) ++{ ++ char buf[] = "0x00000000"; ++ unsigned long len = min(sizeof(buf) - 1, (u32)count); ++ char *p = (char *)buf; ++ unsigned long val; ++ ++ if (copy_from_user(buf, buffer, len)) ++ return count; ++ buf[len] = 0; ++ if (p[1] == 'x' || p[1] == 'X' || p[0] == 'x' || p[0] == 'X') { ++ p++; ++ if (p[0] == 'x' || p[0] == 'X') ++ p++; ++ val = simple_strtoul(p, &p, 16); ++ } else ++ val = simple_strtoul(p, &p, 10); ++ if (p == buf) ++ printk(KERN_INFO DRV_NAME ++ ": %s is not in hex or decimal form.\n", buf); ++ else ++ ieee80211_debug_level = val; ++ ++ return strnlen(buf, count); ++} ++ ++static int __init ieee80211_init(void) ++{ ++ struct proc_dir_entry *e; ++ ++ ieee80211_debug_level = debug; ++ ieee80211_proc = create_proc_entry(DRV_NAME, S_IFDIR, proc_net); ++ if (ieee80211_proc == NULL) { ++ IEEE80211_ERROR("Unable to create " DRV_NAME ++ " proc directory\n"); ++ return -EIO; ++ } ++ e = create_proc_entry("debug_level", S_IFREG | S_IRUGO | S_IWUSR, ++ ieee80211_proc); ++ if (!e) { ++ remove_proc_entry(DRV_NAME, proc_net); ++ ieee80211_proc = NULL; ++ return -EIO; ++ } ++ e->read_proc = show_debug_level; ++ e->write_proc = store_debug_level; ++ e->data = NULL; ++ ++ return 0; ++} ++ ++static void __exit ieee80211_exit(void) ++{ ++ if (ieee80211_proc) { ++ remove_proc_entry("debug_level", ieee80211_proc); ++ remove_proc_entry(DRV_NAME, proc_net); ++ ieee80211_proc = NULL; ++ } ++} ++ ++#include <linux/moduleparam.h> ++module_param(debug, int, 0444); ++MODULE_PARM_DESC(debug, "debug output mask"); ++ ++ ++module_exit(ieee80211_exit); ++module_init(ieee80211_init); ++#endif ++#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0)) ++EXPORT_SYMBOL(alloc_ieee80211); ++EXPORT_SYMBOL(free_ieee80211); ++#else ++EXPORT_SYMBOL_NOVERS(alloc_ieee80211); ++EXPORT_SYMBOL_NOVERS(free_ieee80211); ++#endif +diff -Nur linux-2.6.33/drivers/net/wireless/rtl8187b/ieee80211/ieee80211_rx.c linux-lemote/drivers/net/wireless/rtl8187b/ieee80211/ieee80211_rx.c +--- linux-2.6.33/drivers/net/wireless/rtl8187b/ieee80211/ieee80211_rx.c 1970-01-01 01:00:00.000000000 +0100 ++++ linux-lemote/drivers/net/wireless/rtl8187b/ieee80211/ieee80211_rx.c 2010-03-06 16:43:22.000000000 +0100 +@@ -0,0 +1,2074 @@ ++/* ++ * Original code based Host AP (software wireless LAN access point) driver ++ * for Intersil Prism2/2.5/3 - hostap.o module, common routines ++ * ++ * Copyright (c) 2001-2002, SSH Communications Security Corp and Jouni Malinen ++ * <jkmaline@cc.hut.fi> ++ * Copyright (c) 2002-2003, Jouni Malinen <jkmaline@cc.hut.fi> ++ * Copyright (c) 2004, Intel Corporation ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License version 2 as ++ * published by the Free Software Foundation. See README and COPYING for ++ * more details. ++ ****************************************************************************** ++ ++ Few modifications for Realtek's Wi-Fi drivers by ++ Andrea Merello <andreamrl@tiscali.it> ++ ++ A special thanks goes to Realtek for their support ! ++ ++******************************************************************************/ ++ ++ ++#include <linux/compiler.h> ++//#include <linux/config.h> ++#include <linux/errno.h> ++#include <linux/if_arp.h> ++#include <linux/in6.h> ++#include <linux/in.h> ++#include <linux/ip.h> ++#include <linux/kernel.h> ++#include <linux/module.h> ++#include <linux/netdevice.h> ++#include <linux/pci.h> ++#include <linux/proc_fs.h> ++#include <linux/skbuff.h> ++#include <linux/slab.h> ++#include <linux/tcp.h> ++#include <linux/types.h> ++#include <linux/version.h> ++#include <linux/wireless.h> ++#include <linux/etherdevice.h> ++#include <asm/uaccess.h> ++#include <linux/ctype.h> ++ ++#include "ieee80211.h" ++#ifdef ENABLE_DOT11D ++#include "dot11d.h" ++#endif ++ ++static inline void ieee80211_monitor_rx(struct ieee80211_device *ieee, ++ struct sk_buff *skb, ++ struct ieee80211_rx_stats *rx_stats) ++{ ++ struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data; ++ u16 fc = le16_to_cpu(hdr->frame_ctl); ++ ++ skb->dev = ieee->dev; ++#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,22) ++ skb_reset_mac_header(skb); ++#else ++ skb->mac.raw = skb->data; ++#endif ++ ++ //skb->mac.raw = skb->data; ++ skb_pull(skb, ieee80211_get_hdrlen(fc)); ++ skb->pkt_type = PACKET_OTHERHOST; ++ skb->protocol = __constant_htons(ETH_P_80211_RAW); ++ memset(skb->cb, 0, sizeof(skb->cb)); ++ netif_rx(skb); ++} ++ ++ ++/* Called only as a tasklet (software IRQ) */ ++static struct ieee80211_frag_entry * ++ieee80211_frag_cache_find(struct ieee80211_device *ieee, unsigned int seq, ++ unsigned int frag, u8 tid,u8 *src, u8 *dst) ++{ ++ struct ieee80211_frag_entry *entry; ++ int i; ++ ++ for (i = 0; i < IEEE80211_FRAG_CACHE_LEN; i++) { ++ entry = &ieee->frag_cache[tid][i]; ++ if (entry->skb != NULL && ++ time_after(jiffies, entry->first_frag_time + 2 * HZ)) { ++ IEEE80211_DEBUG_FRAG( ++ "expiring fragment cache entry " ++ "seq=%u last_frag=%u\n", ++ entry->seq, entry->last_frag); ++ dev_kfree_skb_any(entry->skb); ++ entry->skb = NULL; ++ } ++ ++ if (entry->skb != NULL && entry->seq == seq && ++ (entry->last_frag + 1 == frag || frag == -1) && ++ memcmp(entry->src_addr, src, ETH_ALEN) == 0 && ++ memcmp(entry->dst_addr, dst, ETH_ALEN) == 0) ++ return entry; ++ } ++ ++ return NULL; ++} ++ ++/* Called only as a tasklet (software IRQ) */ ++static struct sk_buff * ++ieee80211_frag_cache_get(struct ieee80211_device *ieee, ++ struct ieee80211_hdr *hdr) ++{ ++ struct sk_buff *skb = NULL; ++ u16 fc = le16_to_cpu(hdr->frame_ctl); ++ u16 sc = le16_to_cpu(hdr->seq_ctl); ++ unsigned int frag = WLAN_GET_SEQ_FRAG(sc); ++ unsigned int seq = WLAN_GET_SEQ_SEQ(sc); ++ struct ieee80211_frag_entry *entry; ++ struct ieee80211_hdr_3addr_QOS *hdr_3addr_QoS; ++ struct ieee80211_hdr_QOS *hdr_4addr_QoS; ++ u8 tid; ++ ++#ifdef _RTL8187_EXT_PATCH_ ++ if(ieee->iw_mode == ieee->iw_ext_mode) ++ { ++ tid = (hdr->addr2[ETH_ALEN-2] ^ hdr->addr2[ETH_ALEN-1]) & IEEE80211_QOS_TID; ++ } ++ else ++#endif ++ if (((fc & IEEE80211_FCTL_DSTODS) == IEEE80211_FCTL_DSTODS)&&IEEE80211_QOS_HAS_SEQ(fc)) { ++ hdr_4addr_QoS = (struct ieee80211_hdr_QOS *)hdr; ++ tid = le16_to_cpu(hdr_4addr_QoS->QOS_ctl) & IEEE80211_QOS_TID; ++ tid = UP2AC(tid); ++ tid ++; ++ } else if (IEEE80211_QOS_HAS_SEQ(fc)) { ++ hdr_3addr_QoS = (struct ieee80211_hdr_3addr_QOS *)hdr; ++ tid = le16_to_cpu(hdr_3addr_QoS->QOS_ctl) & IEEE80211_QOS_TID; ++ tid = UP2AC(tid); ++ tid ++; ++ } else { ++ tid = 0; ++ } ++ ++ if (frag == 0) { ++ /* Reserve enough space to fit maximum frame length */ ++ skb = dev_alloc_skb(ieee->dev->mtu + ++ sizeof(struct ieee80211_hdr) + ++ 8 /* LLC */ + ++ 2 /* alignment */ + ++ 8 /* WEP */ + ++ ETH_ALEN /* WDS */ + ++ (IEEE80211_QOS_HAS_SEQ(fc)?2:0) /* QOS Control */); ++ if (skb == NULL) ++ return NULL; ++ ++ entry = &ieee->frag_cache[tid][ieee->frag_next_idx[tid]]; ++ ieee->frag_next_idx[tid]++; ++ if (ieee->frag_next_idx[tid] >= IEEE80211_FRAG_CACHE_LEN) ++ ieee->frag_next_idx[tid] = 0; ++ ++ if (entry->skb != NULL) ++ dev_kfree_skb_any(entry->skb); ++ ++ entry->first_frag_time = jiffies; ++ entry->seq = seq; ++ entry->last_frag = frag; ++ entry->skb = skb; ++ memcpy(entry->src_addr, hdr->addr2, ETH_ALEN); ++ memcpy(entry->dst_addr, hdr->addr1, ETH_ALEN); ++ } else { ++ /* received a fragment of a frame for which the head fragment ++ * should have already been received */ ++ entry = ieee80211_frag_cache_find(ieee, seq, frag, tid,hdr->addr2, ++ hdr->addr1); ++ if (entry != NULL) { ++ entry->last_frag = frag; ++ skb = entry->skb; ++ } ++ } ++ ++ return skb; ++} ++ ++ ++/* Called only as a tasklet (software IRQ) */ ++static int ieee80211_frag_cache_invalidate(struct ieee80211_device *ieee, ++ struct ieee80211_hdr *hdr) ++{ ++ u16 fc = le16_to_cpu(hdr->frame_ctl); ++ u16 sc = le16_to_cpu(hdr->seq_ctl); ++ unsigned int seq = WLAN_GET_SEQ_SEQ(sc); ++ struct ieee80211_frag_entry *entry; ++ struct ieee80211_hdr_3addr_QOS *hdr_3addr_QoS; ++ struct ieee80211_hdr_QOS *hdr_4addr_QoS; ++ u8 tid; ++ ++#ifdef _RTL8187_EXT_PATCH_ ++ if(ieee->iw_mode == ieee->iw_ext_mode) ++ { ++ tid = (hdr->addr2[ETH_ALEN-2] ^ hdr->addr2[ETH_ALEN-1]) & IEEE80211_QOS_TID; ++ } ++ else ++#endif ++ if(((fc & IEEE80211_FCTL_DSTODS) == IEEE80211_FCTL_DSTODS)&&IEEE80211_QOS_HAS_SEQ(fc)) { ++ hdr_4addr_QoS = (struct ieee80211_hdr_QOS *)hdr; ++ tid = le16_to_cpu(hdr_4addr_QoS->QOS_ctl) & IEEE80211_QOS_TID; ++ tid = UP2AC(tid); ++ tid ++; ++ } else if (IEEE80211_QOS_HAS_SEQ(fc)) { ++ hdr_3addr_QoS = (struct ieee80211_hdr_3addr_QOS *)hdr; ++ tid = le16_to_cpu(hdr_3addr_QoS->QOS_ctl) & IEEE80211_QOS_TID; ++ tid = UP2AC(tid); ++ tid ++; ++ } else { ++ tid = 0; ++ } ++ ++ entry = ieee80211_frag_cache_find(ieee, seq, -1, tid,hdr->addr2, ++ hdr->addr1); ++ ++ if (entry == NULL) { ++ IEEE80211_DEBUG_FRAG( ++ "could not invalidate fragment cache " ++ "entry (seq=%u)\n", seq); ++ return -1; ++ } ++ ++ entry->skb = NULL; ++ return 0; ++} ++ ++ ++ ++/* ieee80211_rx_frame_mgtmt ++ * ++ * Responsible for handling management control frames ++ * ++ * Called by ieee80211_rx */ ++static inline int ++ieee80211_rx_frame_mgmt(struct ieee80211_device *ieee, struct sk_buff *skb, ++ struct ieee80211_rx_stats *rx_stats, u16 type, ++ u16 stype) ++{ ++ /* On the struct stats definition there is written that ++ * this is not mandatory.... but seems that the probe ++ * response parser uses it ++ */ ++ struct ieee80211_hdr * hdr = (struct ieee80211_hdr*)skb->data; ++ rx_stats->len = skb->len; ++ ieee80211_rx_mgt(ieee,(struct ieee80211_hdr *)skb->data,rx_stats); ++ ++ if ((ieee->state == IEEE80211_LINKED) && (memcmp(hdr->addr3, ieee->current_network.bssid, ETH_ALEN))) ++ { ++ dev_kfree_skb_any(skb); ++ return 0; ++ } ++ ++ ieee80211_rx_frame_softmac(ieee, skb, rx_stats, type, stype); ++ ++ dev_kfree_skb_any(skb); ++ ++ return 0; ++ ++ #ifdef NOT_YET ++ if (ieee->iw_mode == IW_MODE_MASTER) { ++ printk(KERN_DEBUG "%s: Master mode not yet suppported.\n", ++ ieee->dev->name); ++ return 0; ++/* ++ hostap_update_sta_ps(ieee, (struct hostap_ieee80211_hdr *) ++ skb->data);*/ ++ } ++ ++ if (ieee->hostapd && type == IEEE80211_TYPE_MGMT) { ++ if (stype == WLAN_FC_STYPE_BEACON && ++ ieee->iw_mode == IW_MODE_MASTER) { ++ struct sk_buff *skb2; ++ /* Process beacon frames also in kernel driver to ++ * update STA(AP) table statistics */ ++ skb2 = skb_clone(skb, GFP_ATOMIC); ++ if (skb2) ++ hostap_rx(skb2->dev, skb2, rx_stats); ++ } ++ ++ /* send management frames to the user space daemon for ++ * processing */ ++ ieee->apdevstats.rx_packets++; ++ ieee->apdevstats.rx_bytes += skb->len; ++ prism2_rx_80211(ieee->apdev, skb, rx_stats, PRISM2_RX_MGMT); ++ return 0; ++ } ++ ++ if (ieee->iw_mode == IW_MODE_MASTER) { ++ if (type != WLAN_FC_TYPE_MGMT && type != WLAN_FC_TYPE_CTRL) { ++ printk(KERN_DEBUG "%s: unknown management frame " ++ "(type=0x%02x, stype=0x%02x) dropped\n", ++ skb->dev->name, type, stype); ++ return -1; ++ } ++ ++ hostap_rx(skb->dev, skb, rx_stats); ++ return 0; ++ } ++ ++ printk(KERN_DEBUG "%s: hostap_rx_frame_mgmt: management frame " ++ "received in non-Host AP mode\n", skb->dev->name); ++ return -1; ++ #endif ++} ++ ++ ++ ++/* See IEEE 802.1H for LLC/SNAP encapsulation/decapsulation */ ++/* Ethernet-II snap header (RFC1042 for most EtherTypes) */ ++static unsigned char rfc1042_header[] = ++{ 0xaa, 0xaa, 0x03, 0x00, 0x00, 0x00 }; ++/* Bridge-Tunnel header (for EtherTypes ETH_P_AARP and ETH_P_IPX) */ ++static unsigned char bridge_tunnel_header[] = ++{ 0xaa, 0xaa, 0x03, 0x00, 0x00, 0xf8 }; ++/* No encapsulation header if EtherType < 0x600 (=length) */ ++ ++/* Called by ieee80211_rx_frame_decrypt */ ++static int ieee80211_is_eapol_frame(struct ieee80211_device *ieee, ++ struct sk_buff *skb, size_t hdrlen) ++{ ++ struct net_device *dev = ieee->dev; ++ u16 fc, ethertype; ++ struct ieee80211_hdr *hdr; ++ u8 *pos; ++ ++ if (skb->len < 24) ++ return 0; ++ ++ hdr = (struct ieee80211_hdr *) skb->data; ++ fc = le16_to_cpu(hdr->frame_ctl); ++ ++ /* check that the frame is unicast frame to us */ ++ if ((fc & (IEEE80211_FCTL_TODS | IEEE80211_FCTL_FROMDS)) == ++ IEEE80211_FCTL_TODS && ++ memcmp(hdr->addr1, dev->dev_addr, ETH_ALEN) == 0 && ++ memcmp(hdr->addr3, dev->dev_addr, ETH_ALEN) == 0) { ++ /* ToDS frame with own addr BSSID and DA */ ++ } else if ((fc & (IEEE80211_FCTL_TODS | IEEE80211_FCTL_FROMDS)) == ++ IEEE80211_FCTL_FROMDS && ++ memcmp(hdr->addr1, dev->dev_addr, ETH_ALEN) == 0) { ++ /* FromDS frame with own addr as DA */ ++ } else ++ return 0; ++ ++ if (skb->len < 24 + 8) ++ return 0; ++ ++ /* check for port access entity Ethernet type */ ++// pos = skb->data + 24; ++ pos = skb->data + hdrlen; ++ ethertype = (pos[6] << 8) | pos[7]; ++ if (ethertype == ETH_P_PAE) ++ return 1; ++ ++ return 0; ++} ++ ++/* Called only as a tasklet (software IRQ), by ieee80211_rx */ ++static inline int ++ieee80211_rx_frame_decrypt(struct ieee80211_device* ieee, struct sk_buff *skb, ++ struct ieee80211_crypt_data *crypt) ++{ ++ struct ieee80211_hdr *hdr; ++ int res, hdrlen; ++ ++ if (crypt == NULL || crypt->ops->decrypt_mpdu == NULL) ++ return 0; ++ ++ hdr = (struct ieee80211_hdr *) skb->data; ++#ifdef _RTL8187_EXT_PATCH_ ++ if((ieee->iw_mode == ieee->iw_ext_mode) && (ieee->ext_patch_ieee80211_rx_frame_get_hdrlen)) ++ { ++ hdrlen = ieee->ext_patch_ieee80211_rx_frame_get_hdrlen(ieee, skb); ++ } ++ else ++#endif ++ hdrlen = ieee80211_get_hdrlen(le16_to_cpu(hdr->frame_ctl)); ++ ++#ifdef CONFIG_IEEE80211_CRYPT_TKIP ++ if (ieee->tkip_countermeasures && ++ strcmp(crypt->ops->name, "TKIP") == 0) { ++ if (net_ratelimit()) { ++ printk(KERN_DEBUG "%s: TKIP countermeasures: dropped " ++ "received packet from " MAC_FMT "\n", ++ ieee->dev->name, MAC_ARG(hdr->addr2)); ++ } ++ return -1; ++ } ++#endif ++ ++ atomic_inc(&crypt->refcnt); ++ res = crypt->ops->decrypt_mpdu(skb, hdrlen, crypt->priv); ++ atomic_dec(&crypt->refcnt); ++ if (res < 0) { ++ IEEE80211_DEBUG_DROP( ++ "decryption failed (SA=" MAC_FMT ++ ") res=%d\n", MAC_ARG(hdr->addr2), res); ++ if (res == -2) ++ IEEE80211_DEBUG_DROP("Decryption failed ICV " ++ "mismatch (key %d)\n", ++ skb->data[hdrlen + 3] >> 6); ++ ieee->ieee_stats.rx_discards_undecryptable++; ++ return -1; ++ } ++ ++ return res; ++} ++ ++ ++/* Called only as a tasklet (software IRQ), by ieee80211_rx */ ++static inline int ++ieee80211_rx_frame_decrypt_msdu(struct ieee80211_device* ieee, struct sk_buff *skb, ++ int keyidx, struct ieee80211_crypt_data *crypt) ++{ ++ struct ieee80211_hdr *hdr; ++ int res, hdrlen; ++ ++ if (crypt == NULL || crypt->ops->decrypt_msdu == NULL) ++ return 0; ++ ++ hdr = (struct ieee80211_hdr *) skb->data; ++#ifdef _RTL8187_EXT_PATCH_ ++ if((ieee->iw_mode == ieee->iw_ext_mode) && (ieee->ext_patch_ieee80211_rx_frame_get_hdrlen)) ++ { ++ hdrlen = ieee->ext_patch_ieee80211_rx_frame_get_hdrlen(ieee, skb); ++ } ++ else ++#endif ++ hdrlen = ieee80211_get_hdrlen(le16_to_cpu(hdr->frame_ctl)); ++ ++ atomic_inc(&crypt->refcnt); ++ res = crypt->ops->decrypt_msdu(skb, keyidx, hdrlen, crypt->priv); ++ atomic_dec(&crypt->refcnt); ++ if (res < 0) { ++ printk(KERN_DEBUG "%s: MSDU decryption/MIC verification failed" ++ " (SA=" MAC_FMT " keyidx=%d)\n", ++ ieee->dev->name, MAC_ARG(hdr->addr2), keyidx); ++ return -1; ++ } ++ ++ return 0; ++} ++ ++ ++/* this function is stolen from ipw2200 driver*/ ++#define IEEE_PACKET_RETRY_TIME (5*HZ) ++static int is_duplicate_packet(struct ieee80211_device *ieee, ++ struct ieee80211_hdr *header) ++{ ++ u16 fc = le16_to_cpu(header->frame_ctl); ++ u16 sc = le16_to_cpu(header->seq_ctl); ++ u16 seq = WLAN_GET_SEQ_SEQ(sc); ++ u16 frag = WLAN_GET_SEQ_FRAG(sc); ++ u16 *last_seq, *last_frag; ++ unsigned long *last_time; ++ struct ieee80211_hdr_3addr_QOS *hdr_3addr_QoS; ++ struct ieee80211_hdr_QOS *hdr_4addr_QoS; ++ u8 tid; ++ ++#ifdef _RTL8187_EXT_PATCH_ ++ if(ieee->iw_mode == ieee->iw_ext_mode) ++ { ++ tid = (header->addr2[ETH_ALEN-2] ^ header->addr2[ETH_ALEN-1]) & IEEE80211_QOS_TID; ++ } ++ else ++#endif ++ //TO2DS and QoS ++ if(((fc & IEEE80211_FCTL_DSTODS) == IEEE80211_FCTL_DSTODS)&&IEEE80211_QOS_HAS_SEQ(fc)) { ++ hdr_4addr_QoS = (struct ieee80211_hdr_QOS *)header; ++ tid = le16_to_cpu(hdr_4addr_QoS->QOS_ctl) & IEEE80211_QOS_TID; ++ tid = UP2AC(tid); ++ tid ++; ++ } else if(IEEE80211_QOS_HAS_SEQ(fc)) { //QoS ++ hdr_3addr_QoS = (struct ieee80211_hdr_3addr_QOS*)header; ++ tid = le16_to_cpu(hdr_3addr_QoS->QOS_ctl) & IEEE80211_QOS_TID; ++ tid = UP2AC(tid); ++ tid ++; ++ } else { // no QoS ++ tid = 0; ++ } ++ ++ switch (ieee->iw_mode) { ++ case IW_MODE_ADHOC: ++ { ++ struct list_head *p; ++ struct ieee_ibss_seq *entry = NULL; ++ u8 *mac = header->addr2; ++ int index = mac[5] % IEEE_IBSS_MAC_HASH_SIZE; ++ //for (pos = (head)->next; pos != (head); pos = pos->next) ++ __list_for_each(p, &ieee->ibss_mac_hash[index]) { ++ entry = list_entry(p, struct ieee_ibss_seq, list); ++ if (!memcmp(entry->mac, mac, ETH_ALEN)) ++ break; ++ } ++ // if (memcmp(entry->mac, mac, ETH_ALEN)){ ++ if (p == &ieee->ibss_mac_hash[index]) { ++ entry = kmalloc(sizeof(struct ieee_ibss_seq), GFP_ATOMIC); ++ if (!entry) { ++ printk(KERN_WARNING "Cannot malloc new mac entry\n"); ++ return 0; ++ } ++ memcpy(entry->mac, mac, ETH_ALEN); ++ entry->seq_num[tid] = seq; ++ entry->frag_num[tid] = frag; ++ entry->packet_time[tid] = jiffies; ++ list_add(&entry->list, &ieee->ibss_mac_hash[index]); ++ return 0; ++ } ++ last_seq = &entry->seq_num[tid]; ++ last_frag = &entry->frag_num[tid]; ++ last_time = &entry->packet_time[tid]; ++ break; ++ } ++ ++ case IW_MODE_INFRA: ++ last_seq = &ieee->last_rxseq_num[tid]; ++ last_frag = &ieee->last_rxfrag_num[tid]; ++ last_time = &ieee->last_packet_time[tid]; ++ ++ break; ++ default: ++#ifdef _RTL8187_EXT_PATCH_ ++ if(ieee->iw_mode == ieee->iw_ext_mode) ++ { ++#if 0 ++ printk("==============> tid = %d\n", tid); ++ last_seq = &ieee->last_rxseq_num[tid]; ++ last_frag = &ieee->last_rxfrag_num[tid]; ++ last_time = &ieee->last_packet_time[tid]; ++#else ++ struct list_head *p; ++ struct ieee_mesh_seq *entry = NULL; ++ u8 *mac = header->addr2; ++ int index = mac[5] % IEEE_IBSS_MAC_HASH_SIZE; ++ ++ __list_for_each(p, &ieee->mesh_mac_hash[index]) { ++ entry = list_entry(p, struct ieee_mesh_seq, list); ++ if (!memcmp(entry->mac, mac, ETH_ALEN)) ++ break; ++ } ++ if (p == &ieee->mesh_mac_hash[index]) { ++ entry = kmalloc(sizeof(struct ieee_mesh_seq), GFP_ATOMIC); ++ if (!entry) { ++ printk(KERN_WARNING "Cannot malloc new mac entry for mesh\n"); ++ return 0; ++ } ++ memcpy(entry->mac, mac, ETH_ALEN); ++ entry->seq_num = seq; ++ entry->frag_num = frag; ++ entry->packet_time = jiffies; ++ list_add(&entry->list, &ieee->mesh_mac_hash[index]); ++ return 0; ++ } ++ last_seq = &entry->seq_num; ++ last_frag = &entry->frag_num; ++ last_time = &entry->packet_time; ++#endif ++ break; ++ } ++ else ++#endif ++ return 0; ++ } ++ ++// if(tid != 0) { ++// printk(KERN_WARNING ":)))))))))))%x %x %x, fc(%x)\n", tid, *last_seq, seq, header->frame_ctl); ++// } ++ if ((*last_seq == seq) && ++ time_after(*last_time + IEEE_PACKET_RETRY_TIME, jiffies)) { ++ if (*last_frag == frag){ ++ //printk(KERN_WARNING "[1] go drop!\n"); ++ goto drop; ++ ++ } ++ if (*last_frag + 1 != frag) ++ /* out-of-order fragment */ ++ //printk(KERN_WARNING "[2] go drop!\n"); ++ goto drop; ++ } else ++ *last_seq = seq; ++ ++ *last_frag = frag; ++ *last_time = jiffies; ++ return 0; ++ ++drop: ++// BUG_ON(!(fc & IEEE80211_FCTL_RETRY)); ++// printk("DUP\n"); ++ ++ return 1; ++} ++#ifdef JUST_FOR_87SEMESH ++#define ActionHeadLen 30 ++#define WIFI_MESH_TYPE IEEE80211_FTYPE_DATA ++#define WIFI_11S_MESH_ACTION 0x00A0 ++#endif ++ ++/* All received frames are sent to this function. @skb contains the frame in ++ * IEEE 802.11 format, i.e., in the format it was sent over air. ++ * This function is called only as a tasklet (software IRQ). */ ++int ieee80211_rx(struct ieee80211_device *ieee, struct sk_buff *skb, ++ struct ieee80211_rx_stats *rx_stats) ++{ ++ struct net_device *dev = ieee->dev; ++ struct ieee80211_hdr *hdr; ++ //struct ieee80211_hdr_3addr_QOS *hdr; ++ ++ size_t hdrlen; ++ u16 fc, type, stype, sc; ++ struct net_device_stats *stats; ++ unsigned int frag; ++ u8 *payload; ++ u16 ethertype; ++#ifdef NOT_YET ++ struct net_device *wds = NULL; ++ struct sk_buff *skb2 = NULL; ++ struct net_device *wds = NULL; ++ int frame_authorized = 0; ++ int from_assoc_ap = 0; ++ void *sta = NULL; ++#endif ++// u16 QOS_ctl = 0; ++ u8 dst[ETH_ALEN]; ++ u8 src[ETH_ALEN]; ++ u8 bssid[ETH_ALEN]; ++ struct ieee80211_crypt_data *crypt = NULL; ++ int keyidx = 0; ++ ++ //Added for mesh by Lawrence. ++ //u8 status; ++ //u32 flags; ++ ++ // cheat the the hdr type ++ hdr = (struct ieee80211_hdr *)skb->data; ++ stats = &ieee->stats; ++ ++ if (skb->len < 10) { ++ printk(KERN_INFO "%s: SKB length < 10\n", ++ dev->name); ++ goto rx_dropped; ++ } ++#if 0 ++//{added by david for filter the packet listed in the filter table ++#ifdef _RTL8187_EXT_PATCH_ ++ if((ieee->iw_mode == ieee->iw_ext_mode) && (ieee->ext_patch_ieee80211_acl_query)) ++ { ++ if(!ieee->ext_patch_ieee80211_acl_query(ieee, hdr->addr2)) ++ goto rx_dropped; ++ } ++#endif ++//} ++#endif ++ fc = le16_to_cpu(hdr->frame_ctl); ++ type = WLAN_FC_GET_TYPE(fc); ++ stype = WLAN_FC_GET_STYPE(fc); ++ ++ //Because 87se's bad feature,do more handle. ++#ifdef JUST_FOR_87SEMESH ++ ++u8 tmphead[ActionHeadLen]; ++ if(type ==WIFI_MESH_TYPE && stype== WIFI_11S_MESH_ACTION ) ++ //head=sizeof(struct ieee80211_hdr)=30 ++ { ++ memset(tmphead,0,ActionHeadLen); ++ memcpy(tmphead,skb->data,ActionHeadLen); ++ ++ skb_pull(skb,ActionHeadLen+2); ++ memcpy(skb_push(skb,ActionHeadLen),tmphead,ActionHeadLen); ++ hdr = (struct ieee80211_hdr *)skb->data; ++ } ++ ++#endif ++ sc = le16_to_cpu(hdr->seq_ctl); ++ ++ frag = WLAN_GET_SEQ_FRAG(sc); ++#ifdef _RTL8187_EXT_PATCH_ ++ if((ieee->iw_mode == ieee->iw_ext_mode) && (ieee->ext_patch_ieee80211_rx_frame_get_hdrlen)) ++ { ++ hdrlen = ieee->ext_patch_ieee80211_rx_frame_get_hdrlen(ieee, skb); ++ if(skb->len < hdrlen) ++ goto rx_dropped; ++ } ++ else ++#endif ++ hdrlen = ieee80211_get_hdrlen(fc); ++ ++#ifdef NOT_YET ++#if WIRELESS_EXT > 15 ++ /* Put this code here so that we avoid duplicating it in all ++ * Rx paths. - Jean II */ ++#ifdef IW_WIRELESS_SPY /* defined in iw_handler.h */ ++ /* If spy monitoring on */ ++ if (iface->spy_data.spy_number > 0) { ++ struct iw_quality wstats; ++ wstats.level = rx_stats->signal; ++ wstats.noise = rx_stats->noise; ++ wstats.updated = 6; /* No qual value */ ++ /* Update spy records */ ++ wireless_spy_update(dev, hdr->addr2, &wstats); ++ } ++#endif /* IW_WIRELESS_SPY */ ++#endif /* WIRELESS_EXT > 15 */ ++ hostap_update_rx_stats(local->ap, hdr, rx_stats); ++#endif ++ ++#if WIRELESS_EXT > 15 ++ if (ieee->iw_mode == IW_MODE_MONITOR) { ++ ieee80211_monitor_rx(ieee, skb, rx_stats); ++ stats->rx_packets++; ++ stats->rx_bytes += skb->len; ++ return 1; ++ } ++#endif ++ if (ieee->host_decrypt) { ++ int idx = 0; ++ if (skb->len >= hdrlen + 3) ++ idx = skb->data[hdrlen + 3] >> 6; ++#ifdef _RTL8187_EXT_PATCH_ ++ ++ crypt = ieee->cryptlist[0]->crypt[idx]; ++#if 0 ++ { ++ int i = ieee80211_find_MP(ieee, ((struct ieee80211_hdr*)skb->data)->addr2); ++ if (i == -1) ++ { ++ printk("error find entry in entry list\n"); ++ goto rx_dropped; ++ } ++ //printk("%s():"MAC_FMT", find in index:%d", __FUNCTION__, MAC_ARG(((struct ieee80211_hdr*)skb->data)->addr2), i); ++ crypt = ieee->cryptlist[i]->crypt[idx]; ++ } ++#endif ++#else ++ crypt = ieee->crypt[idx]; ++#endif ++ ++#ifdef NOT_YET ++ sta = NULL; ++ ++ /* Use station specific key to override default keys if the ++ * receiver address is a unicast address ("individual RA"). If ++ * bcrx_sta_key parameter is set, station specific key is used ++ * even with broad/multicast targets (this is against IEEE ++ * 802.11, but makes it easier to use different keys with ++ * stations that do not support WEP key mapping). */ ++ ++ if (!(hdr->addr1[0] & 0x01) || local->bcrx_sta_key) ++ (void) hostap_handle_sta_crypto(local, hdr, &crypt, ++ &sta); ++#endif ++ ++ /* allow NULL decrypt to indicate an station specific override ++ * for default encryption */ ++ if (crypt && (crypt->ops == NULL || ++ crypt->ops->decrypt_mpdu == NULL)) ++ crypt = NULL; ++ ++ if (!crypt && (fc & IEEE80211_FCTL_WEP)) { ++ /* This seems to be triggered by some (multicast?) ++ * frames from other than current BSS, so just drop the ++ * frames silently instead of filling system log with ++ * these reports. */ ++ IEEE80211_DEBUG_DROP("Decryption failed (not set)" ++ " (SA=" MAC_FMT ")\n", ++ MAC_ARG(hdr->addr2)); ++ ieee->ieee_stats.rx_discards_undecryptable++; ++ goto rx_dropped; ++ } ++ } ++ ++ if (skb->len < IEEE80211_DATA_HDR3_LEN) ++ goto rx_dropped; ++ ++ // if QoS enabled, should check the sequence for each of the AC ++ if (is_duplicate_packet(ieee, hdr)) ++ goto rx_dropped; ++ ++#ifdef _RTL8187_EXT_PATCH_ ++ if( ieee->iw_mode == ieee->iw_ext_mode && ieee->ext_patch_ieee80211_rx_mgt_update_expire ) ++ ieee->ext_patch_ieee80211_rx_mgt_update_expire( ieee, skb ); ++#endif ++ ++ if (type == IEEE80211_FTYPE_MGMT) { ++ ++ #if 0 ++ if ( stype == IEEE80211_STYPE_AUTH && ++ fc & IEEE80211_FCTL_WEP && ieee->host_decrypt && ++ (keyidx = hostap_rx_frame_decrypt(ieee, skb, crypt)) < 0) ++ { ++ printk(KERN_DEBUG "%s: failed to decrypt mgmt::auth " ++ "from " MAC_FMT "\n", dev->name, ++ MAC_ARG(hdr->addr2)); ++ /* TODO: could inform hostapd about this so that it ++ * could send auth failure report */ ++ goto rx_dropped; ++ } ++ #endif ++ ++ ++ if (ieee80211_rx_frame_mgmt(ieee, skb, rx_stats, type, stype)) ++ goto rx_dropped; ++ else ++ goto rx_exit; ++ } ++ ++#ifdef _RTL8187_EXT_PATCH_ ++ if((ieee->iw_mode == ieee->iw_ext_mode) && ieee->ext_patch_ieee80211_rx_on_rx) ++ { ++ if(ieee->ext_patch_ieee80211_rx_on_rx(ieee, skb, rx_stats, type, stype)==0) ++ { ++ goto rx_exit; ++ } ++ } ++#endif ++ ++ /* Data frame - extract src/dst addresses */ ++ switch (fc & (IEEE80211_FCTL_FROMDS | IEEE80211_FCTL_TODS)) { ++ case IEEE80211_FCTL_FROMDS: ++ memcpy(dst, hdr->addr1, ETH_ALEN); ++ memcpy(src, hdr->addr3, ETH_ALEN); ++ memcpy(bssid, hdr->addr2, ETH_ALEN); ++ break; ++ case IEEE80211_FCTL_TODS: ++ memcpy(dst, hdr->addr3, ETH_ALEN); ++ memcpy(src, hdr->addr2, ETH_ALEN); ++ memcpy(bssid, hdr->addr1, ETH_ALEN); ++ break; ++ case IEEE80211_FCTL_FROMDS | IEEE80211_FCTL_TODS: ++ if (skb->len < IEEE80211_DATA_HDR4_LEN) ++ goto rx_dropped; ++ memcpy(dst, hdr->addr3, ETH_ALEN); ++ memcpy(src, hdr->addr4, ETH_ALEN); ++ memcpy(bssid, ieee->current_network.bssid, ETH_ALEN); ++ break; ++ case 0: ++ memcpy(dst, hdr->addr1, ETH_ALEN); ++ memcpy(src, hdr->addr2, ETH_ALEN); ++ memcpy(bssid, hdr->addr3, ETH_ALEN); ++ break; ++ } ++ ++#ifdef NOT_YET ++ if (hostap_rx_frame_wds(ieee, hdr, fc, &wds)) ++ goto rx_dropped; ++ if (wds) { ++ skb->dev = dev = wds; ++ stats = hostap_get_stats(dev); ++ } ++ ++ if (ieee->iw_mode == IW_MODE_MASTER && !wds && ++ (fc & (IEEE80211_FCTL_TODS | IEEE80211_FCTL_FROMDS)) == IEEE80211_FCTL_FROMDS && ++ ieee->stadev && ++ memcmp(hdr->addr2, ieee->assoc_ap_addr, ETH_ALEN) == 0) { ++ /* Frame from BSSID of the AP for which we are a client */ ++ skb->dev = dev = ieee->stadev; ++ stats = hostap_get_stats(dev); ++ from_assoc_ap = 1; ++ } ++#endif ++ ++ dev->last_rx = jiffies; ++ ++#ifdef NOT_YET ++ if ((ieee->iw_mode == IW_MODE_MASTER || ++ ieee->iw_mode == IW_MODE_REPEAT) && ++ !from_assoc_ap) { ++ switch (hostap_handle_sta_rx(ieee, dev, skb, rx_stats, ++ wds != NULL)) { ++ case AP_RX_CONTINUE_NOT_AUTHORIZED: ++ frame_authorized = 0; ++ break; ++ case AP_RX_CONTINUE: ++ frame_authorized = 1; ++ break; ++ case AP_RX_DROP: ++ goto rx_dropped; ++ case AP_RX_EXIT: ++ goto rx_exit; ++ } ++ } ++#endif ++ ++#ifdef _RTL8187_EXT_PATCH_ ++ if((ieee->iw_mode == ieee->iw_ext_mode) && ieee->ext_patch_ieee80211_rx_is_valid_framectl) ++ { ++ if(ieee->ext_patch_ieee80211_rx_is_valid_framectl(ieee, fc, type, stype)==0) ++ goto rx_dropped; ++ } ++ else ++#endif ++ /* Nullfunc frames may have PS-bit set, so they must be passed to ++ * hostap_handle_sta_rx() before being dropped here. */ ++ if (stype != IEEE80211_STYPE_DATA && ++ stype != IEEE80211_STYPE_DATA_CFACK && ++ stype != IEEE80211_STYPE_DATA_CFPOLL && ++ stype != IEEE80211_STYPE_DATA_CFACKPOLL&& ++ stype != IEEE80211_STYPE_QOS_DATA//add by David,2006.8.4 ++ ) { ++ if (stype != IEEE80211_STYPE_NULLFUNC) ++ IEEE80211_DEBUG_DROP( ++ "RX: dropped data frame " ++ "with no data (type=0x%02x, " ++ "subtype=0x%02x, len=%d)\n", ++ type, stype, skb->len); ++ goto rx_dropped; ++ } ++ ++ if (memcmp(bssid, ieee->current_network.bssid, ETH_ALEN)) ++ goto rx_dropped; ++ ++ /* skb: hdr + (possibly fragmented, possibly encrypted) payload */ ++#ifdef _RTL8187_EXT_PATCH_ ++ if (ieee->host_decrypt && crypt) { ++ int idx = 0; ++ if (skb->len >= hdrlen + 3) ++ idx = skb->data[hdrlen + 3] >> 6; ++ if (ieee->iw_ext_mode == ieee->iw_mode) //if in mesh mode ++ { ++ int i = ieee80211_find_MP(ieee, ((struct ieee80211_hdr*)skb->data)->addr2, 0); ++ if (i == -1) ++ { ++ printk("error find entry in entry list\n"); ++ goto rx_dropped; ++ } ++ // printk("%s():"MAC_FMT", find in index:%d\n", __FUNCTION__, MAC_ARG(((struct ieee80211_hdr*)skb->data)->addr2), i); ++ if (ieee->cryptlist[i]&&ieee->cryptlist[i]->crypt[idx]) ++ crypt = ieee->cryptlist[i]->crypt[idx]; ++ ++ else ++ crypt = NULL; ++ } ++ else ++ crypt = ieee->cryptlist[0]->crypt[idx]; ++ } ++#endif ++ ++ if (ieee->host_decrypt && (fc & IEEE80211_FCTL_WEP) && ++ (keyidx = ieee80211_rx_frame_decrypt(ieee, skb, crypt)) < 0) ++ goto rx_dropped; ++ ++ hdr = (struct ieee80211_hdr *) skb->data; ++ ++ /* skb: hdr + (possibly fragmented) plaintext payload */ ++ // PR: FIXME: hostap has additional conditions in the "if" below: ++ // ieee->host_decrypt && (fc & IEEE80211_FCTL_WEP) && ++ if ((frag != 0 || (fc & IEEE80211_FCTL_MOREFRAGS))) { ++ int flen; ++ struct sk_buff *frag_skb = ieee80211_frag_cache_get(ieee, hdr); ++ IEEE80211_DEBUG_FRAG("Rx Fragment received (%u)\n", frag); ++ ++ if (!frag_skb) { ++ IEEE80211_DEBUG(IEEE80211_DL_RX | IEEE80211_DL_FRAG, ++ "Rx cannot get skb from fragment " ++ "cache (morefrag=%d seq=%u frag=%u)\n", ++ (fc & IEEE80211_FCTL_MOREFRAGS) != 0, ++ WLAN_GET_SEQ_SEQ(sc), frag); ++ goto rx_dropped; ++ } ++ flen = skb->len; ++ if (frag != 0) ++ flen -= hdrlen; ++ ++ if (frag_skb->tail + flen > frag_skb->end) { ++ printk(KERN_WARNING "%s: host decrypted and " ++ "reassembled frame did not fit skb\n", ++ dev->name); ++ ieee80211_frag_cache_invalidate(ieee, hdr); ++ goto rx_dropped; ++ } ++ ++ if (frag == 0) { ++ /* copy first fragment (including full headers) into ++ * beginning of the fragment cache skb */ ++ memcpy(skb_put(frag_skb, flen), skb->data, flen); ++ } else { ++ /* append frame payload to the end of the fragment ++ * cache skb */ ++ memcpy(skb_put(frag_skb, flen), skb->data + hdrlen, ++ flen); ++ } ++ dev_kfree_skb_any(skb); ++ skb = NULL; ++ ++ if (fc & IEEE80211_FCTL_MOREFRAGS) { ++ /* more fragments expected - leave the skb in fragment ++ * cache for now; it will be delivered to upper layers ++ * after all fragments have been received */ ++ goto rx_exit; ++ } ++ ++ /* this was the last fragment and the frame will be ++ * delivered, so remove skb from fragment cache */ ++ skb = frag_skb; ++ hdr = (struct ieee80211_hdr *) skb->data; ++ ieee80211_frag_cache_invalidate(ieee, hdr); ++ } ++ ++ /* skb: hdr + (possible reassembled) full MSDU payload; possibly still ++ * encrypted/authenticated */ ++ if (ieee->host_decrypt && (fc & IEEE80211_FCTL_WEP) && ++ ieee80211_rx_frame_decrypt_msdu(ieee, skb, keyidx, crypt)) ++ goto rx_dropped; ++ ++ hdr = (struct ieee80211_hdr *) skb->data; ++ if (crypt && !(fc & IEEE80211_FCTL_WEP) && !ieee->open_wep) { ++ if (/*ieee->ieee802_1x &&*/ ++ ieee80211_is_eapol_frame(ieee, skb, hdrlen)) { ++ ++#ifdef CONFIG_IEEE80211_DEBUG ++ /* pass unencrypted EAPOL frames even if encryption is ++ * configured */ ++ struct eapol *eap = (struct eapol *)(skb->data + ++ 24); ++ IEEE80211_DEBUG_EAP("RX: IEEE 802.1X EAPOL frame: %s\n", ++ eap_get_type(eap->type)); ++#endif ++ } else { ++ IEEE80211_DEBUG_DROP( ++ "encryption configured, but RX " ++ "frame not encrypted (SA=" MAC_FMT ")\n", ++ MAC_ARG(hdr->addr2)); ++ goto rx_dropped; ++ } ++ } ++ ++#ifdef CONFIG_IEEE80211_DEBUG ++ if (crypt && !(fc & IEEE80211_FCTL_WEP) && ++ ieee80211_is_eapol_frame(ieee, skb)) { ++ struct eapol *eap = (struct eapol *)(skb->data + ++ 24); ++ IEEE80211_DEBUG_EAP("RX: IEEE 802.1X EAPOL frame: %s\n", ++ eap_get_type(eap->type)); ++ } ++#endif ++ ++ if (crypt && !(fc & IEEE80211_FCTL_WEP) && !ieee->open_wep && ++ !ieee80211_is_eapol_frame(ieee, skb, hdrlen)) { ++ IEEE80211_DEBUG_DROP( ++ "dropped unencrypted RX data " ++ "frame from " MAC_FMT ++ " (drop_unencrypted=1)\n", ++ MAC_ARG(hdr->addr2)); ++ goto rx_dropped; ++ } ++/* ++ if(ieee80211_is_eapol_frame(ieee, skb, hdrlen)) { ++ printk(KERN_WARNING "RX: IEEE802.1X EPAOL frame!\n"); ++ } ++*/ ++ /* skb: hdr + (possible reassembled) full plaintext payload */ ++ payload = skb->data + hdrlen; ++ ethertype = (payload[6] << 8) | payload[7]; ++ ++#ifdef NOT_YET ++ /* If IEEE 802.1X is used, check whether the port is authorized to send ++ * the received frame. */ ++ if (ieee->ieee802_1x && ieee->iw_mode == IW_MODE_MASTER) { ++ if (ethertype == ETH_P_PAE) { ++ printk(KERN_DEBUG "%s: RX: IEEE 802.1X frame\n", ++ dev->name); ++ if (ieee->hostapd && ieee->apdev) { ++ /* Send IEEE 802.1X frames to the user ++ * space daemon for processing */ ++ prism2_rx_80211(ieee->apdev, skb, rx_stats, ++ PRISM2_RX_MGMT); ++ ieee->apdevstats.rx_packets++; ++ ieee->apdevstats.rx_bytes += skb->len; ++ goto rx_exit; ++ } ++ } else if (!frame_authorized) { ++ printk(KERN_DEBUG "%s: dropped frame from " ++ "unauthorized port (IEEE 802.1X): " ++ "ethertype=0x%04x\n", ++ dev->name, ethertype); ++ goto rx_dropped; ++ } ++ } ++#endif ++ ++#ifdef _RTL8187_EXT_PATCH_ ++ if((ieee->iw_mode == ieee->iw_ext_mode) && ieee->ext_patch_ieee80211_rx_process_dataframe) ++ { ++ if(ieee->ext_patch_ieee80211_rx_process_dataframe(ieee, skb, rx_stats)) ++ { ++ stats->rx_packets++; ++ stats->rx_bytes += skb->len; ++ goto rx_exit; ++ } ++ else ++ goto rx_dropped; ++ } ++#endif ++ ieee->NumRxDataInPeriod++; ++// ieee->NumRxOkTotal++; ++ /* convert hdr + possible LLC headers into Ethernet header */ ++ if (skb->len - hdrlen >= 8 && ++ ((memcmp(payload, rfc1042_header, SNAP_SIZE) == 0 && ++ ethertype != ETH_P_AARP && ethertype != ETH_P_IPX) || ++ memcmp(payload, bridge_tunnel_header, SNAP_SIZE) == 0)) { ++ /* remove RFC1042 or Bridge-Tunnel encapsulation and ++ * replace EtherType */ ++ skb_pull(skb, hdrlen + SNAP_SIZE); ++ memcpy(skb_push(skb, ETH_ALEN), src, ETH_ALEN); ++ memcpy(skb_push(skb, ETH_ALEN), dst, ETH_ALEN); ++ } else { ++ u16 len; ++ /* Leave Ethernet header part of hdr and full payload */ ++ skb_pull(skb, hdrlen); ++ len = htons(skb->len); ++ memcpy(skb_push(skb, 2), &len, 2); ++ memcpy(skb_push(skb, ETH_ALEN), src, ETH_ALEN); ++ memcpy(skb_push(skb, ETH_ALEN), dst, ETH_ALEN); ++ } ++ ++#ifdef NOT_YET ++ if (wds && ((fc & (IEEE80211_FCTL_TODS | IEEE80211_FCTL_FROMDS)) == ++ IEEE80211_FCTL_TODS) && ++ skb->len >= ETH_HLEN + ETH_ALEN) { ++ /* Non-standard frame: get addr4 from its bogus location after ++ * the payload */ ++ memcpy(skb->data + ETH_ALEN, ++ skb->data + skb->len - ETH_ALEN, ETH_ALEN); ++ skb_trim(skb, skb->len - ETH_ALEN); ++ } ++#endif ++ ++ stats->rx_packets++; ++ stats->rx_bytes += skb->len; ++ ++#ifdef NOT_YET ++ if (ieee->iw_mode == IW_MODE_MASTER && !wds && ++ ieee->ap->bridge_packets) { ++ if (dst[0] & 0x01) { ++ /* copy multicast frame both to the higher layers and ++ * to the wireless media */ ++ ieee->ap->bridged_multicast++; ++ skb2 = skb_clone(skb, GFP_ATOMIC); ++ if (skb2 == NULL) ++ printk(KERN_DEBUG "%s: skb_clone failed for " ++ "multicast frame\n", dev->name); ++ } else if (hostap_is_sta_assoc(ieee->ap, dst)) { ++ /* send frame directly to the associated STA using ++ * wireless media and not passing to higher layers */ ++ ieee->ap->bridged_unicast++; ++ skb2 = skb; ++ skb = NULL; ++ } ++ } ++ ++ if (skb2 != NULL) { ++ /* send to wireless media */ ++ skb2->protocol = __constant_htons(ETH_P_802_3); ++ skb2->mac.raw = skb2->nh.raw = skb2->data; ++ /* skb2->nh.raw = skb2->data + ETH_HLEN; */ ++ skb2->dev = dev; ++ dev_queue_xmit(skb2); ++ } ++ ++#endif ++ if (skb) { ++ //printk("0skb_len(%d)\n", skb->len); ++ skb->protocol = eth_type_trans(skb, dev); ++ memset(skb->cb, 0, sizeof(skb->cb)); ++ skb->dev = dev; ++ skb->ip_summed = CHECKSUM_NONE; /* 802.11 crc not sufficient */ ++ //skb->ip_summed = CHECKSUM_UNNECESSARY; /* 802.11 crc not sufficient */ ++ ieee->last_rx_ps_time = jiffies; ++ //printk("1skb_len(%d)\n", skb->len); ++ netif_rx(skb); ++ } ++ ++//by lizhaoming for LED_RX 2008.6.23 ++#ifdef LED_SHIN ++// printk("==================>data rcvd\n"); ++ ieee->ieee80211_led_contorl(dev,LED_CTL_RX); ++#endif ++ ++ rx_exit: ++#ifdef NOT_YET ++ if (sta) ++ hostap_handle_sta_release(sta); ++#endif ++ return 1; ++ ++ rx_dropped: ++ stats->rx_dropped++; ++#if 0 ++ int i; ++ printk("======>dropped: %s():addr2:"MAC_FMT",addr1:"MAC_FMT",skb->len:%d, hdrlen:%d\n", __FUNCTION__, MAC_ARG(((struct ieee80211_hdr*)skb->data)->addr2), MAC_ARG(((struct ieee80211_hdr*)skb->data)->addr1), skb->len, hdrlen); ++ for (i = 0; i < skb->len; i++) { ++ if (i % 16 == 0) printk("\n\t"); ++ printk("%2x ", *(skb->data+i)); ++ } ++ ++ printk("\n"); ++#endif ++ /* Returning 0 indicates to caller that we have not handled the SKB-- ++ * so it is still allocated and can be used again by underlying ++ * hardware as a DMA target */ ++ return 0; ++} ++ ++#ifdef _RTL8187_EXT_PATCH_ ++int ieee_ext_skb_p80211_to_ether(struct sk_buff *skb, int hdrlen, u8 *dst, u8 *src) ++{ ++ u8 *payload; ++ u16 ethertype; ++ ++ /* skb: hdr + (possible reassembled) full plaintext payload */ ++ payload = skb->data + hdrlen; ++ ethertype = (payload[6] << 8) | payload[7]; ++ ++ /* convert hdr + possible LLC headers into Ethernet header */ ++ if (skb->len - hdrlen >= 8 && ++ ((memcmp(payload, rfc1042_header, SNAP_SIZE) == 0 && ++ ethertype != ETH_P_AARP && ethertype != ETH_P_IPX) || ++ memcmp(payload, bridge_tunnel_header, SNAP_SIZE) == 0)) { ++ /* remove RFC1042 or Bridge-Tunnel encapsulation and ++ * replace EtherType */ ++ skb_pull(skb, hdrlen + SNAP_SIZE); ++ memcpy(skb_push(skb, ETH_ALEN), src, ETH_ALEN); ++ memcpy(skb_push(skb, ETH_ALEN), dst, ETH_ALEN); ++ } else { ++ u16 len; ++ /* Leave Ethernet header part of hdr and full payload */ ++ skb_pull(skb, hdrlen); ++ len = htons(skb->len); ++ memcpy(skb_push(skb, 2), &len, 2); ++ memcpy(skb_push(skb, ETH_ALEN), src, ETH_ALEN); ++ memcpy(skb_push(skb, ETH_ALEN), dst, ETH_ALEN); ++ } ++ ++ return 1; ++} ++#endif // _RTL8187_EXT_PATCH_ ++ ++ ++#define MGMT_FRAME_FIXED_PART_LENGTH 0x24 ++ ++static inline int ieee80211_is_ofdm_rate(u8 rate) ++{ ++ switch (rate & ~IEEE80211_BASIC_RATE_MASK) { ++ case IEEE80211_OFDM_RATE_6MB: ++ case IEEE80211_OFDM_RATE_9MB: ++ case IEEE80211_OFDM_RATE_12MB: ++ case IEEE80211_OFDM_RATE_18MB: ++ case IEEE80211_OFDM_RATE_24MB: ++ case IEEE80211_OFDM_RATE_36MB: ++ case IEEE80211_OFDM_RATE_48MB: ++ case IEEE80211_OFDM_RATE_54MB: ++ return 1; ++ } ++ return 0; ++} ++ ++ ++// ++// Description: ++// Translate 0-100 signal strength index into dBm. ++// ++int ++TranslateToDbm8187( ++ unsigned char SignalStrengthIndex // 0-100 index. ++ ) ++{ ++ unsigned char SignalPower; // in dBm. ++ ++ // Translate to dBm (x=0.5y-95). ++ //SignalPower = (int)((SignalStrengthIndex + 1) >> 1); ++ SignalPower = (int)SignalStrengthIndex * 7 / 10; ++ SignalPower -= 95; ++// printk("==>SignalPower:%d\n", SignalPower); ++ return SignalPower; ++} ++ ++static inline int ieee80211_SignalStrengthTranslate( ++ int CurrSS ++ ) ++{ ++ int RetSS; ++ ++ // Step 1. Scale mapping. ++ if(CurrSS >= 71 && CurrSS <= 100) ++ { ++ RetSS = 95 + (((CurrSS - 70) / 6 == 5) ? 5 : ((CurrSS - 70) / 6 + 1)); ++ } ++ else if(CurrSS >= 41 && CurrSS <= 70) ++ { ++ RetSS = 83 + ((CurrSS - 40) / 3); ++ } ++ else if(CurrSS >= 31 && CurrSS <= 40) ++ { ++ RetSS = 71 + (CurrSS - 30); ++ } ++ else if(CurrSS >= 21 && CurrSS <= 30) ++ { ++ RetSS = 59 + (CurrSS - 20); ++ } ++ else if(CurrSS >= 5 && CurrSS <= 20) ++ { ++ RetSS = 47 + (((CurrSS - 5) * 2) / 3); ++ } ++ else if(CurrSS == 4) ++ { ++ RetSS = 37; ++ } ++ else if(CurrSS == 3) ++ { ++ RetSS = 27; ++ } ++ else if(CurrSS == 2) ++ { ++ RetSS = 18; ++ } ++ else if(CurrSS == 1) ++ { ++ RetSS = 9; ++ } ++ else ++ { ++ RetSS = CurrSS; ++ } ++ //RT_TRACE(COMP_DBG, DBG_LOUD, ("##### After Mapping: LastSS: %d, CurrSS: %d, RetSS: %d\n", LastSS, CurrSS, RetSS)); ++ ++ // Step 2. Smoothing. ++ ++ //RT_TRACE(COMP_DBG, DBG_LOUD, ("$$$$$ After Smoothing: LastSS: %d, CurrSS: %d, RetSS: %d\n", LastSS, CurrSS, RetSS)); ++ ++ return RetSS; ++} ++ ++#ifdef ENABLE_DOT11D ++static inline void ieee80211_extract_country_ie( ++ struct ieee80211_device *ieee, ++ struct ieee80211_info_element *info_element, ++ struct ieee80211_network *network, ++ u8 * addr2 ++) ++{ ++#if 0 ++ u32 i = 0; ++ u8 * p = (u8*)info_element->data; ++ printk("-----------------------\n"); ++ printk("%s Country IE:", network->ssid); ++ for(i=0; i<info_element->len; i++) ++ printk("\t%2.2x", *(p+i)); ++ printk("\n-----------------------\n"); ++#endif ++ if(IS_DOT11D_ENABLE(ieee)) ++ { ++ if(info_element->len!= 0) ++ { ++ memcpy(network->CountryIeBuf, info_element->data, info_element->len); ++ network->CountryIeLen = info_element->len; ++ ++ if(!IS_COUNTRY_IE_VALID(ieee)) ++ { ++ Dot11d_UpdateCountryIe(ieee, addr2, info_element->len, info_element->data); ++ } ++ } ++ ++ // ++ // 070305, rcnjko: I update country IE watch dog here because ++ // some AP (e.g. Cisco 1242) don't include country IE in their ++ // probe response frame. ++ // ++ if(IS_EQUAL_CIE_SRC(ieee, addr2) ) ++ { ++ UPDATE_CIE_WATCHDOG(ieee); ++ } ++ } ++ ++} ++#endif ++ ++ ++ inline int ieee80211_network_init( ++ struct ieee80211_device *ieee, ++ struct ieee80211_probe_response *beacon, ++ struct ieee80211_network *network, ++ struct ieee80211_rx_stats *stats) ++{ ++#ifdef CONFIG_IEEE80211_DEBUG ++ char rates_str[64]; ++ char *p; ++#endif ++ struct ieee80211_info_element *info_element; ++ u16 left; ++ u8 i; ++ short offset; ++ ++ /* Pull out fixed field data */ ++ memcpy(network->bssid, beacon->header.addr3, ETH_ALEN); ++ network->capability = beacon->capability; ++ network->last_scanned = jiffies; ++ network->time_stamp[0] = beacon->time_stamp[0]; ++ network->time_stamp[1] = beacon->time_stamp[1]; ++ network->beacon_interval = beacon->beacon_interval; ++ /* Where to pull this? beacon->listen_interval;*/ ++ network->listen_interval = 0x0A; ++ network->rates_len = network->rates_ex_len = 0; ++ network->last_associate = 0; ++ network->ssid_len = 0; ++ network->flags = 0; ++ network->atim_window = 0; ++ network->QoS_Enable = 0; ++#ifdef THOMAS_TURBO ++ network->Turbo_Enable = 0; ++#endif ++#ifdef ENABLE_DOT11D ++ network->CountryIeLen = 0; ++ memset(network->CountryIeBuf, 0, MAX_IE_LEN); ++#endif ++ ++ if (stats->freq == IEEE80211_52GHZ_BAND) { ++ /* for A band (No DS info) */ ++ network->channel = stats->received_channel; ++ } else ++ network->flags |= NETWORK_HAS_CCK; ++ ++ network->wpa_ie_len = 0; ++ network->rsn_ie_len = 0; ++ ++ info_element = &beacon->info_element; ++ left = stats->len - ((void *)info_element - (void *)beacon); ++ while (left >= sizeof(struct ieee80211_info_element_hdr)) { ++ if (sizeof(struct ieee80211_info_element_hdr) + info_element->len > left) { ++ IEEE80211_DEBUG_SCAN("SCAN: parse failed: info_element->len + 2 > left : info_element->len+2=%d left=%d.\n", ++ info_element->len + sizeof(struct ieee80211_info_element), ++ left); ++ return 1; ++ } ++ ++ switch (info_element->id) { ++ case MFIE_TYPE_SSID: ++ if (ieee80211_is_empty_essid(info_element->data, ++ info_element->len)) { ++ network->flags |= NETWORK_EMPTY_ESSID; ++ break; ++ } ++ ++ network->ssid_len = min(info_element->len, ++ (u8)IW_ESSID_MAX_SIZE); ++ memcpy(network->ssid, info_element->data, network->ssid_len); ++ if (network->ssid_len < IW_ESSID_MAX_SIZE) ++ memset(network->ssid + network->ssid_len, 0, ++ IW_ESSID_MAX_SIZE - network->ssid_len); ++ ++ IEEE80211_DEBUG_SCAN("MFIE_TYPE_SSID: '%s' len=%d.\n", ++ network->ssid, network->ssid_len); ++ break; ++ ++ case MFIE_TYPE_RATES: ++#ifdef CONFIG_IEEE80211_DEBUG ++ p = rates_str; ++#endif ++ network->rates_len = min(info_element->len, MAX_RATES_LENGTH); ++ for (i = 0; i < network->rates_len; i++) { ++ network->rates[i] = info_element->data[i]; ++#ifdef CONFIG_IEEE80211_DEBUG ++ p += snprintf(p, sizeof(rates_str) - (p - rates_str), "%02X ", network->rates[i]); ++#endif ++ if (ieee80211_is_ofdm_rate(info_element->data[i])) { ++ network->flags |= NETWORK_HAS_OFDM; ++ if (info_element->data[i] & ++ IEEE80211_BASIC_RATE_MASK) ++ network->flags &= ++ ~NETWORK_HAS_CCK; ++ } ++ } ++ ++ IEEE80211_DEBUG_SCAN("MFIE_TYPE_RATES: '%s' (%d)\n", ++ rates_str, network->rates_len); ++ break; ++ ++ case MFIE_TYPE_RATES_EX: ++#ifdef CONFIG_IEEE80211_DEBUG ++ p = rates_str; ++#endif ++ network->rates_ex_len = min(info_element->len, MAX_RATES_EX_LENGTH); ++ for (i = 0; i < network->rates_ex_len; i++) { ++ network->rates_ex[i] = info_element->data[i]; ++#ifdef CONFIG_IEEE80211_DEBUG ++ p += snprintf(p, sizeof(rates_str) - (p - rates_str), "%02X ", network->rates[i]); ++#endif ++ if (ieee80211_is_ofdm_rate(info_element->data[i])) { ++ network->flags |= NETWORK_HAS_OFDM; ++ if (info_element->data[i] & ++ IEEE80211_BASIC_RATE_MASK) ++ network->flags &= ++ ~NETWORK_HAS_CCK; ++ } ++ } ++ ++ IEEE80211_DEBUG_SCAN("MFIE_TYPE_RATES_EX: '%s' (%d)\n", ++ rates_str, network->rates_ex_len); ++ break; ++ ++ case MFIE_TYPE_DS_SET: ++ IEEE80211_DEBUG_SCAN("MFIE_TYPE_DS_SET: %d\n", ++ info_element->data[0]); ++ if (stats->freq == IEEE80211_24GHZ_BAND) ++ network->channel = info_element->data[0]; ++ break; ++ ++ case MFIE_TYPE_FH_SET: ++ IEEE80211_DEBUG_SCAN("MFIE_TYPE_FH_SET: ignored\n"); ++ break; ++ ++ case MFIE_TYPE_CF_SET: ++ IEEE80211_DEBUG_SCAN("MFIE_TYPE_CF_SET: ignored\n"); ++ break; ++ ++ case MFIE_TYPE_TIM: ++ ++ if(info_element->len < 4) ++ break; ++ ++ network->dtim_period = info_element->data[1]; ++ ++ if(ieee->state != IEEE80211_LINKED) ++ break; ++ ++ network->last_dtim_sta_time[0] = stats->mac_time[0]; ++ network->last_dtim_sta_time[1] = stats->mac_time[1]; ++ ++ network->dtim_data = IEEE80211_DTIM_VALID; ++ ++ if(info_element->data[0] != 0) ++ break; ++ ++ if(info_element->data[2] & 1) ++ network->dtim_data |= IEEE80211_DTIM_MBCAST; ++ ++ offset = (info_element->data[2] >> 1)*2; ++ ++ //printk("offset1:%x aid:%x\n",offset, ieee->assoc_id); ++ ++ if(ieee->assoc_id < offset || ++ ieee->assoc_id > 8*(offset + info_element->len -3)) ++ ++ break; ++ ++ ++ offset = offset + ieee->assoc_id / 8;// + ((aid % 8)? 0 : 1) ; ++ ++ // printk("offset:%x data:%x, ucast:%d\n", offset, ++ // info_element->data[3+offset] , ++ // info_element->data[3+offset] & (1<<(ieee->assoc_id%8))); ++ ++ if(info_element->data[3+offset] & (1<<(ieee->assoc_id%8))) ++ network->dtim_data |= IEEE80211_DTIM_UCAST; ++ ++ break; ++ ++ case MFIE_TYPE_IBSS_SET: ++ IEEE80211_DEBUG_SCAN("MFIE_TYPE_IBSS_SET: ignored\n"); ++ break; ++ ++ case MFIE_TYPE_CHALLENGE: ++ IEEE80211_DEBUG_SCAN("MFIE_TYPE_CHALLENGE: ignored\n"); ++ break; ++ ++ case MFIE_TYPE_GENERIC: ++ //nic is 87B ++ IEEE80211_DEBUG_SCAN("MFIE_TYPE_GENERIC: %d bytes\n", ++ info_element->len); ++ if (info_element->len >= 4 && ++ info_element->data[0] == 0x00 && ++ info_element->data[1] == 0x50 && ++ info_element->data[2] == 0xf2 && ++ info_element->data[3] == 0x01) { ++ network->wpa_ie_len = min(info_element->len + 2, ++ MAX_WPA_IE_LEN); ++ memcpy(network->wpa_ie, info_element, ++ network->wpa_ie_len); ++ } ++ ++#ifdef THOMAS_TURBO ++ if (info_element->len == 7 && ++ info_element->data[0] == 0x00 && ++ info_element->data[1] == 0xe0 && ++ info_element->data[2] == 0x4c && ++ info_element->data[3] == 0x01 && ++ info_element->data[4] == 0x02) { ++ network->Turbo_Enable = 1; ++ } ++#endif ++ if (1 == stats->nic_type) {//nic 87 ++ break; ++ } ++ ++ if (info_element->len >= 5 && ++ info_element->data[0] == 0x00 && ++ info_element->data[1] == 0x50 && ++ info_element->data[2] == 0xf2 && ++ info_element->data[3] == 0x02 && ++ info_element->data[4] == 0x00) { ++ //printk(KERN_WARNING "wmm info updated: %x\n", info_element->data[6]); ++ //WMM Information Element ++ network->wmm_info = info_element->data[6]; ++ network->QoS_Enable = 1; ++ } ++ ++ if (info_element->len >= 8 && ++ info_element->data[0] == 0x00 && ++ info_element->data[1] == 0x50 && ++ info_element->data[2] == 0xf2 && ++ info_element->data[3] == 0x02 && ++ info_element->data[4] == 0x01) { ++ // Not care about version at present. ++ //WMM Information Element ++ //printk(KERN_WARNING "wmm info¶m updated: %x\n", info_element->data[6]); ++ network->wmm_info = info_element->data[6]; ++ //WMM Parameter Element ++ memcpy(network->wmm_param, (u8 *)(info_element->data + 8),(info_element->len - 8)); ++ network->QoS_Enable = 1; ++ } ++ break; ++ ++ case MFIE_TYPE_RSN: ++ IEEE80211_DEBUG_SCAN("MFIE_TYPE_RSN: %d bytes\n", ++ info_element->len); ++ network->rsn_ie_len = min(info_element->len + 2, ++ MAX_WPA_IE_LEN); ++ memcpy(network->rsn_ie, info_element, ++ network->rsn_ie_len); ++ break; ++ ++#ifdef ENABLE_DOT11D ++ case MFIE_TYPE_COUNTRY: ++ IEEE80211_DEBUG_SCAN("MFIE_TYPE_COUNTRY: %d bytes\n", ++ info_element->len); ++// printk("=====>Receive <%s> Country IE\n",network->ssid); ++ ieee80211_extract_country_ie(ieee, info_element, network, beacon->header.addr2); ++ break; ++#endif ++ ++ default: ++ IEEE80211_DEBUG_SCAN("unsupported IE %d\n", ++ info_element->id); ++ break; ++ } ++ ++ left -= sizeof(struct ieee80211_info_element_hdr) + ++ info_element->len; ++ info_element = (struct ieee80211_info_element *) ++ &info_element->data[info_element->len]; ++ } ++ ++ network->mode = 0; ++ if (stats->freq == IEEE80211_52GHZ_BAND) ++ network->mode = IEEE_A; ++ else { ++ if (network->flags & NETWORK_HAS_OFDM) ++ network->mode |= IEEE_G; ++ if (network->flags & NETWORK_HAS_CCK) ++ network->mode |= IEEE_B; ++ } ++ ++ if (network->mode == 0) { ++ IEEE80211_DEBUG_SCAN("Filtered out '%s (" MAC_FMT ")' " ++ "network.\n", ++ escape_essid(network->ssid, ++ network->ssid_len), ++ MAC_ARG(network->bssid)); ++ return 1; ++ } ++ ++ if (ieee80211_is_empty_essid(network->ssid, network->ssid_len)) ++ network->flags |= NETWORK_EMPTY_ESSID; ++ ++#if 1 ++ //if(strcmp(network->ssid, "linksys_lzm000") == 0) ++ // printk("----signalstrength = %d ", stats->signalstrength); ++ stats->signal = TranslateToDbm8187(stats->signalstrength); ++ //stats->noise = stats->signal - stats->noise; ++ stats->noise = TranslateToDbm8187(100 - stats->signalstrength) - 25; ++#endif ++ memcpy(&network->stats, stats, sizeof(network->stats)); ++ ++ //YJ,test,080611 ++ //if(strcmp(network->ssid, "ZyXEL") == 0) ++ // IEEE_NET_DUMP(network); ++ ++ return 0; ++} ++ ++static inline int is_same_network(struct ieee80211_network *src, ++ struct ieee80211_network *dst, ++ struct ieee80211_device * ieee) ++{ ++ /* A network is only a duplicate if the channel, BSSID, ESSID ++ * and the capability field (in particular IBSS and BSS) all match. ++ * We treat all <hidden> with the same BSSID and channel ++ * as one network */ ++ return (((src->ssid_len == dst->ssid_len) || (ieee->iw_mode == IW_MODE_INFRA)) && //YJ,mod,080819,for hidden ap ++ //((src->ssid_len == dst->ssid_len) && ++ (src->channel == dst->channel) && ++ !memcmp(src->bssid, dst->bssid, ETH_ALEN) && ++ (!memcmp(src->ssid, dst->ssid, src->ssid_len) || (ieee->iw_mode == IW_MODE_INFRA)) && //YJ,mod,080819,for hidden ap ++ //!memcmp(src->ssid, dst->ssid, src->ssid_len) && ++ ((src->capability & WLAN_CAPABILITY_IBSS) == ++ (dst->capability & WLAN_CAPABILITY_IBSS)) && ++ ((src->capability & WLAN_CAPABILITY_BSS) == ++ (dst->capability & WLAN_CAPABILITY_BSS))); ++} ++ ++inline void update_network(struct ieee80211_network *dst, ++ struct ieee80211_network *src) ++{ ++ unsigned char quality = src->stats.signalstrength; ++ unsigned char signal = 0; ++ unsigned char noise = 0; ++ if(dst->stats.signalstrength > 0) { ++ quality = (dst->stats.signalstrength * 5 + src->stats.signalstrength + 5)/6; ++ } ++ signal = TranslateToDbm8187(quality); ++ //noise = signal - src->stats.noise; ++ if(dst->stats.noise > 0) ++ noise = (dst->stats.noise * 5 + src->stats.noise)/6; ++ //if(strcmp(dst->ssid, "linksys_lzm000") == 0) ++// printk("ssid:%s, quality:%d, signal:%d\n", dst->ssid, quality, signal); ++ memcpy(&dst->stats, &src->stats, sizeof(struct ieee80211_rx_stats)); ++ dst->stats.signalstrength = quality; ++ dst->stats.signal = signal; ++ dst->stats.noise = noise; ++ dst->capability = src->capability; ++ memcpy(dst->rates, src->rates, src->rates_len); ++ dst->rates_len = src->rates_len; ++ memcpy(dst->rates_ex, src->rates_ex, src->rates_ex_len); ++ dst->rates_ex_len = src->rates_ex_len; ++ ++ //YJ,add,080819,for hidden ap ++ if(src->ssid_len > 0) ++ { ++ //if(src->ssid_len == 13) ++ // printk("=====================>>>>>>>> Dst ssid: %s Src ssid: %s\n", dst->ssid, src->ssid); ++ memset(dst->ssid, 0, dst->ssid_len); ++ dst->ssid_len = src->ssid_len; ++ memcpy(dst->ssid, src->ssid, src->ssid_len); ++ } ++ //YJ,add,080819,for hidden ap,end ++ dst->channel = src->channel; ++ dst->mode = src->mode; ++ dst->flags = src->flags; ++ dst->time_stamp[0] = src->time_stamp[0]; ++ dst->time_stamp[1] = src->time_stamp[1]; ++ ++ dst->beacon_interval = src->beacon_interval; ++ dst->listen_interval = src->listen_interval; ++ dst->atim_window = src->atim_window; ++ dst->dtim_period = src->dtim_period; ++ dst->dtim_data = src->dtim_data; ++ dst->last_dtim_sta_time[0] = src->last_dtim_sta_time[0]; ++ dst->last_dtim_sta_time[1] = src->last_dtim_sta_time[1]; ++ ++ memcpy(dst->wpa_ie, src->wpa_ie, src->wpa_ie_len); ++ dst->wpa_ie_len = src->wpa_ie_len; ++ memcpy(dst->rsn_ie, src->rsn_ie, src->rsn_ie_len); ++ dst->rsn_ie_len = src->rsn_ie_len; ++ ++ dst->last_scanned = jiffies; ++ /* dst->last_associate is not overwritten */ ++#if 1 ++ dst->wmm_info = src->wmm_info; //sure to exist in beacon or probe response frame. ++/* ++ if((dst->wmm_info^src->wmm_info)&0x0f) {//Param Set Count change, update Parameter ++ memcpy(dst->wmm_param, src->wmm_param, IEEE80211_AC_PRAM_LEN); ++ } ++*/ ++ if(src->wmm_param[0].ac_aci_acm_aifsn|| \ ++ src->wmm_param[1].ac_aci_acm_aifsn|| \ ++ src->wmm_param[2].ac_aci_acm_aifsn|| \ ++ src->wmm_param[1].ac_aci_acm_aifsn) { ++ memcpy(dst->wmm_param, src->wmm_param, WME_AC_PRAM_LEN); ++ } ++ dst->QoS_Enable = src->QoS_Enable; ++#else ++ dst->QoS_Enable = 1;//for Rtl8187 simulation ++#endif ++ dst->SignalStrength = src->SignalStrength; ++#ifdef THOMAS_TURBO ++ dst->Turbo_Enable = src->Turbo_Enable; ++#endif ++#ifdef ENABLE_DOT11D ++ dst->CountryIeLen = src->CountryIeLen; ++ memcpy(dst->CountryIeBuf, src->CountryIeBuf, src->CountryIeLen); ++#endif ++ ++} ++ ++inline void ieee80211_process_probe_response( ++ struct ieee80211_device *ieee, ++ struct ieee80211_probe_response *beacon, ++ struct ieee80211_rx_stats *stats) ++{ ++ struct ieee80211_network network; ++ struct ieee80211_network *target; ++ struct ieee80211_network *oldest = NULL; ++#ifdef CONFIG_IEEE80211_DEBUG ++ struct ieee80211_info_element *info_element = &beacon->info_element; ++#endif ++ unsigned long flags; ++ short renew; ++ u8 wmm_info; ++ u8 is_beacon = (WLAN_FC_GET_STYPE(beacon->header.frame_ctl) == IEEE80211_STYPE_BEACON)? 1:0; ++ ++ memset(&network, 0, sizeof(struct ieee80211_network)); ++//rz ++#ifdef _RTL8187_EXT_PATCH_ ++ if((ieee->iw_mode == ieee->iw_ext_mode) && ieee->ext_patch_ieee80211_process_probe_response_1) { ++ ieee->ext_patch_ieee80211_process_probe_response_1(ieee, beacon, stats); ++ return; ++ } ++#endif ++ IEEE80211_DEBUG_SCAN( ++ "'%s' (" MAC_FMT "): %c%c%c%c %c%c%c%c-%c%c%c%c %c%c%c%c\n", ++ escape_essid(info_element->data, info_element->len), ++ MAC_ARG(beacon->header.addr3), ++ (beacon->capability & (1<<0xf)) ? '1' : '0', ++ (beacon->capability & (1<<0xe)) ? '1' : '0', ++ (beacon->capability & (1<<0xd)) ? '1' : '0', ++ (beacon->capability & (1<<0xc)) ? '1' : '0', ++ (beacon->capability & (1<<0xb)) ? '1' : '0', ++ (beacon->capability & (1<<0xa)) ? '1' : '0', ++ (beacon->capability & (1<<0x9)) ? '1' : '0', ++ (beacon->capability & (1<<0x8)) ? '1' : '0', ++ (beacon->capability & (1<<0x7)) ? '1' : '0', ++ (beacon->capability & (1<<0x6)) ? '1' : '0', ++ (beacon->capability & (1<<0x5)) ? '1' : '0', ++ (beacon->capability & (1<<0x4)) ? '1' : '0', ++ (beacon->capability & (1<<0x3)) ? '1' : '0', ++ (beacon->capability & (1<<0x2)) ? '1' : '0', ++ (beacon->capability & (1<<0x1)) ? '1' : '0', ++ (beacon->capability & (1<<0x0)) ? '1' : '0'); ++ ++ if (ieee80211_network_init(ieee, beacon, &network, stats)) { ++ IEEE80211_DEBUG_SCAN("Dropped '%s' (" MAC_FMT ") via %s.\n", ++ escape_essid(info_element->data, ++ info_element->len), ++ MAC_ARG(beacon->header.addr3), ++ WLAN_FC_GET_STYPE(beacon->header.frame_ctl) == ++ IEEE80211_STYPE_PROBE_RESP ? ++ "PROBE RESPONSE" : "BEACON"); ++ return; ++ } ++ ++#ifdef ENABLE_DOT11D ++ // For Asus EeePc request, ++ // (1) if wireless adapter receive get any 802.11d country code in AP beacon, ++ // wireless adapter should follow the country code. ++ // (2) If there is no any country code in beacon, ++ // then wireless adapter should do active scan from ch1~11 and ++ // passive scan from ch12~14 ++ if(ieee->bGlobalDomain) ++ { ++ if (WLAN_FC_GET_STYPE(beacon->header.frame_ctl) == IEEE80211_STYPE_PROBE_RESP) ++ { ++ // Case 1: Country code ++ if(IS_COUNTRY_IE_VALID(ieee) ) ++ { ++ if( !IsLegalChannel(ieee, network.channel) ) ++ { ++ printk("GetScanInfo(): For Country code, filter probe response at channel(%d).\n", network.channel); ++ return; ++ } ++ } ++ // Case 2: No any country code. ++ else ++ { ++ // Filter over channel ch12~14 ++ if(network.channel > 11) ++ { ++ printk("GetScanInfo(): For Global Domain, filter probe response at channel(%d).\n", network.channel); ++ return; ++ } ++ } ++ } ++ else ++ { ++ // Case 1: Country code ++ if(IS_COUNTRY_IE_VALID(ieee) ) ++ { ++ if( !IsLegalChannel(ieee, network.channel) ) ++ { ++ printk("GetScanInfo(): For Country code, filter beacon at channel(%d).\n",network.channel); ++ return; ++ } ++ } ++ // Case 2: No any country code. ++ else ++ { ++ // Filter over channel ch12~14 ++ if(network.channel > 14) ++ { ++ printk("GetScanInfo(): For Global Domain, filter beacon at channel(%d).\n",network.channel); ++ return; ++ } ++ } ++ } ++ } ++ ++ //lzm add 081205 ++ // for Toshiba request, we use channel_plan COUNTRY_CODE_WORLD_WIDE_13_INDEX, ++ // For Liteon "World Wide 13" Domain name:ch1~11 active scan & ch12~13 passive scan ++ // So we shoud only rcv beacon in 12-13, and filter probe resp in 12-13. ++ if(ieee->MinPassiveChnlNum != MAX_CHANNEL_NUMBER+1) ++ { ++ if (WLAN_FC_GET_STYPE(beacon->header.frame_ctl) == IEEE80211_STYPE_PROBE_RESP) ++ { ++ // Filter over channel ch12~13 ++ if(network.channel >= ieee->MinPassiveChnlNum) ++ { ++ printk("GetScanInfo(): passive scan, filter probe resp at channel(%d).\n", network.channel); ++ return; ++ } ++ } ++ } ++#endif ++ ++ ++ /* The network parsed correctly -- so now we scan our known networks ++ * to see if we can find it in our list. ++ * ++ * NOTE: This search is definitely not optimized. Once its doing ++ * the "right thing" we'll optimize it for efficiency if ++ * necessary */ ++ ++ /* Search for this entry in the list and update it if it is ++ * already there. */ ++ ++ spin_lock_irqsave(&ieee->lock, flags); ++ ++ if(is_same_network(&ieee->current_network, &network, ieee)) { ++ //YJ,add,080819,for hidden ap ++ if(is_beacon == 0) ++ network.flags = (~NETWORK_EMPTY_ESSID & network.flags)|(NETWORK_EMPTY_ESSID & ieee->current_network.flags); ++ if ((ieee->state == IEEE80211_LINKED) && is_beacon) ++ ieee->NumRxBcnInPeriod++; ++ wmm_info = ieee->current_network.wmm_info; ++ update_network(&ieee->current_network, &network); ++ } ++ ++ list_for_each_entry(target, &ieee->network_list, list) { ++ if (is_same_network(target, &network, ieee)) ++ break; ++ if ((oldest == NULL) || ++ (target->last_scanned < oldest->last_scanned)) ++ oldest = target; ++ } ++ ++ /* If we didn't find a match, then get a new network slot to initialize ++ * with this beacon's information */ ++ if (&target->list == &ieee->network_list) { ++ if (list_empty(&ieee->network_free_list)) { ++ /* If there are no more slots, expire the oldest */ ++ list_del(&oldest->list); ++ target = oldest; ++ IEEE80211_DEBUG_SCAN("Expired '%s' (" MAC_FMT ") from " ++ "network list.\n", ++ escape_essid(target->ssid, ++ target->ssid_len), ++ MAC_ARG(target->bssid)); ++ } else { ++ /* Otherwise just pull from the free list */ ++ target = list_entry(ieee->network_free_list.next, ++ struct ieee80211_network, list); ++ list_del(ieee->network_free_list.next); ++ } ++ ++ ++#ifdef CONFIG_IEEE80211_DEBUG ++ IEEE80211_DEBUG_SCAN("Adding '%s' (" MAC_FMT ") via %s.\n", ++ escape_essid(network.ssid, ++ network.ssid_len), ++ MAC_ARG(network.bssid), ++ WLAN_FC_GET_STYPE(beacon->header.frame_ctl) == ++ IEEE80211_STYPE_PROBE_RESP ? ++ "PROBE RESPONSE" : "BEACON"); ++#endif ++ ++#ifdef _RTL8187_EXT_PATCH_ ++ network.ext_entry = target->ext_entry; ++#endif ++ memcpy(target, &network, sizeof(*target)); ++ list_add_tail(&target->list, &ieee->network_list); ++ if(ieee->softmac_features & IEEE_SOFTMAC_ASSOCIATE) ++ ieee80211_softmac_new_net(ieee,&network); ++ } else { ++ IEEE80211_DEBUG_SCAN("Updating '%s' (" MAC_FMT ") via %s.\n", ++ escape_essid(target->ssid, ++ target->ssid_len), ++ MAC_ARG(target->bssid), ++ WLAN_FC_GET_STYPE(beacon->header.frame_ctl) == ++ IEEE80211_STYPE_PROBE_RESP ? ++ "PROBE RESPONSE" : "BEACON"); ++ ++ /* we have an entry and we are going to update it. But this entry may ++ * be already expired. In this case we do the same as we found a new ++ * net and call the new_net handler ++ */ ++ renew = !time_after(target->last_scanned + ieee->scan_age, jiffies); ++ //YJ,add,080819,for hidden ap ++ if(is_beacon == 0) ++ network.flags = (~NETWORK_EMPTY_ESSID & network.flags)|(NETWORK_EMPTY_ESSID & target->flags); ++ //if(strncmp(network.ssid, "linksys-c",9) == 0) ++ // printk("====>2 network.ssid=%s FLAG=%d target.ssid=%s FLAG=%d\n", network.ssid, network.flags, target->ssid, target->flags); ++ if(((network.flags & NETWORK_EMPTY_ESSID) == NETWORK_EMPTY_ESSID) \ ++ && (((network.ssid_len > 0) && (strncmp(target->ssid, network.ssid, network.ssid_len)))\ ++ ||((ieee->current_network.ssid_len == network.ssid_len)&&(strncmp(ieee->current_network.ssid, network.ssid, network.ssid_len) == 0)&&(ieee->state == IEEE80211_NOLINK)))) ++ renew = 1; ++ //YJ,add,080819,for hidden ap,end ++ update_network(target, &network); ++ if(renew && (ieee->softmac_features & IEEE_SOFTMAC_ASSOCIATE)) ++ ieee80211_softmac_new_net(ieee,&network); ++ } ++ ++ spin_unlock_irqrestore(&ieee->lock, flags); ++} ++ ++void ieee80211_rx_mgt(struct ieee80211_device *ieee, ++ struct ieee80211_hdr *header, ++ struct ieee80211_rx_stats *stats) ++{ ++ switch (WLAN_FC_GET_STYPE(header->frame_ctl)) { ++ ++ case IEEE80211_STYPE_BEACON: ++ IEEE80211_DEBUG_MGMT("received BEACON (%d)\n", ++ WLAN_FC_GET_STYPE(header->frame_ctl)); ++ IEEE80211_DEBUG_SCAN("Beacon\n"); ++ ieee80211_process_probe_response( ++ ieee, (struct ieee80211_probe_response *)header, stats); ++ break; ++ ++ case IEEE80211_STYPE_PROBE_RESP: ++ IEEE80211_DEBUG_MGMT("received PROBE RESPONSE (%d)\n", ++ WLAN_FC_GET_STYPE(header->frame_ctl)); ++ IEEE80211_DEBUG_SCAN("Probe response\n"); ++ ieee80211_process_probe_response( ++ ieee, (struct ieee80211_probe_response *)header, stats); ++ break; ++//rz ++#ifdef _RTL8187_EXT_PATCH_ ++ case IEEE80211_STYPE_PROBE_REQ: ++ IEEE80211_DEBUG_MGMT("received PROBE REQUEST (%d)\n", ++ WLAN_FC_GET_STYPE(header->frame_ctl)); ++ IEEE80211_DEBUG_SCAN("Probe request\n"); ++ /// ++ //printk("Probe request\n"); ++ if( ieee->iw_mode == ieee->iw_ext_mode && ieee->ext_patch_ieee80211_rx_mgt_on_probe_req ) ++ ieee->ext_patch_ieee80211_rx_mgt_on_probe_req( ieee, (struct ieee80211_probe_request *)header, stats); ++ break; ++#endif // _RTL8187_EXT_PATCH_ ++ ++ } ++} ++ ++#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0)) ++EXPORT_SYMBOL(ieee80211_rx_mgt); ++EXPORT_SYMBOL(ieee80211_rx); ++EXPORT_SYMBOL(ieee80211_network_init); ++#ifdef _RTL8187_EXT_PATCH_ ++EXPORT_SYMBOL(ieee_ext_skb_p80211_to_ether); ++#endif ++#else ++EXPORT_SYMBOL_NOVERS(ieee80211_rx_mgt); ++EXPORT_SYMBOL_NOVERS(ieee80211_rx); ++EXPORT_SYMBOL_NOVERS(ieee80211_network_init); ++#ifdef _RTL8187_EXT_PATCH_ ++EXPORT_SYMBOL_NOVERS(ieee_ext_skb_p80211_to_ether); ++#endif ++#endif +diff -Nur linux-2.6.33/drivers/net/wireless/rtl8187b/ieee80211/ieee80211_softmac.c linux-lemote/drivers/net/wireless/rtl8187b/ieee80211/ieee80211_softmac.c +--- linux-2.6.33/drivers/net/wireless/rtl8187b/ieee80211/ieee80211_softmac.c 1970-01-01 01:00:00.000000000 +0100 ++++ linux-lemote/drivers/net/wireless/rtl8187b/ieee80211/ieee80211_softmac.c 2010-03-06 16:43:22.000000000 +0100 +@@ -0,0 +1,4083 @@ ++/* IEEE 802.11 SoftMAC layer ++ * Copyright (c) 2005 Andrea Merello <andreamrl@tiscali.it> ++ * ++ * Mostly extracted from the rtl8180-sa2400 driver for the ++ * in-kernel generic ieee802.11 stack. ++ * ++ * Few lines might be stolen from other part of the ieee80211 ++ * stack. Copyright who own it's copyright ++ * ++ * WPA code stolen from the ipw2200 driver. ++ * Copyright who own it's copyright. ++ * ++ * released under the GPL ++ */ ++ ++ ++#include "ieee80211.h" ++ ++#include <linux/random.h> ++#include <linux/delay.h> ++#include <linux/version.h> ++#include <asm/uaccess.h> ++ ++#ifdef ENABLE_DOT11D ++#include "dot11d.h" ++#endif ++ ++ ++u8 rsn_authen_cipher_suite[16][4] = { ++ {0x00,0x0F,0xAC,0x00}, //Use group key, //Reserved ++ {0x00,0x0F,0xAC,0x01}, //WEP-40 //RSNA default ++ {0x00,0x0F,0xAC,0x02}, //TKIP //NONE //{used just as default} ++ {0x00,0x0F,0xAC,0x03}, //WRAP-historical ++ {0x00,0x0F,0xAC,0x04}, //CCMP ++ {0x00,0x0F,0xAC,0x05}, //WEP-104 ++}; ++ ++short ieee80211_is_54g(struct ieee80211_network net) ++{ ++ return ((net.rates_ex_len > 0) || (net.rates_len > 4)); ++} ++ ++short ieee80211_is_shortslot(struct ieee80211_network net) ++{ ++ return (net.capability & WLAN_CAPABILITY_SHORT_SLOT); ++} ++ ++/* returns the total length needed for pleacing the RATE MFIE ++ * tag and the EXTENDED RATE MFIE tag if needed. ++ * It encludes two bytes per tag for the tag itself and its len ++ */ ++unsigned int ieee80211_MFIE_rate_len(struct ieee80211_device *ieee) ++{ ++ unsigned int rate_len = 0; ++ ++ if (ieee->modulation & IEEE80211_CCK_MODULATION) ++ rate_len = IEEE80211_CCK_RATE_LEN + 2; ++ ++ if (ieee->modulation & IEEE80211_OFDM_MODULATION) ++ ++ rate_len += IEEE80211_OFDM_RATE_LEN + 2; ++ ++ return rate_len; ++} ++ ++/* pleace the MFIE rate, tag to the memory (double) poined. ++ * Then it updates the pointer so that ++ * it points after the new MFIE tag added. ++ */ ++void ieee80211_MFIE_Brate(struct ieee80211_device *ieee, u8 **tag_p) ++{ ++ u8 *tag = *tag_p; ++ ++ if (ieee->modulation & IEEE80211_CCK_MODULATION){ ++ *tag++ = MFIE_TYPE_RATES; ++ *tag++ = 7; ++ *tag++ = IEEE80211_BASIC_RATE_MASK | IEEE80211_CCK_RATE_1MB; ++ *tag++ = IEEE80211_BASIC_RATE_MASK | IEEE80211_CCK_RATE_2MB; ++ *tag++ = IEEE80211_BASIC_RATE_MASK | IEEE80211_CCK_RATE_5MB; ++ *tag++ = IEEE80211_BASIC_RATE_MASK | IEEE80211_CCK_RATE_11MB; ++ //added for basic rate set ++ *tag++ = IEEE80211_BASIC_RATE_MASK | IEEE80211_OFDM_RATE_6MB; ++ *tag++ = IEEE80211_BASIC_RATE_MASK | IEEE80211_OFDM_RATE_12MB; ++ *tag++ = IEEE80211_BASIC_RATE_MASK | IEEE80211_OFDM_RATE_24MB; ++ } ++ ++ /* We may add an option for custom rates that specific HW might support */ ++ *tag_p = tag; ++} ++ ++void ieee80211_MFIE_Grate(struct ieee80211_device *ieee, u8 **tag_p) ++{ ++ u8 *tag = *tag_p; ++ ++ if (ieee->modulation & IEEE80211_OFDM_MODULATION){ ++ ++ *tag++ = MFIE_TYPE_RATES_EX; ++ *tag++ = 5; ++ *tag++ = IEEE80211_OFDM_RATE_9MB; ++ *tag++ = IEEE80211_OFDM_RATE_18MB; ++ *tag++ = IEEE80211_OFDM_RATE_36MB; ++ *tag++ = IEEE80211_OFDM_RATE_48MB; ++ *tag++ = IEEE80211_OFDM_RATE_54MB; ++ ++ } ++ ++ /* We may add an option for custom rates that specific HW might support */ ++ *tag_p = tag; ++} ++ ++ ++void ieee80211_WMM_Info(struct ieee80211_device *ieee, u8 **tag_p) { ++ u8 *tag = *tag_p; ++ ++ *tag++ = MFIE_TYPE_GENERIC; //0 ++ *tag++ = 7; ++ *tag++ = 0x00; ++ *tag++ = 0x50; ++ *tag++ = 0xf2; ++ *tag++ = 0x02;//5 ++ *tag++ = 0x00; ++ *tag++ = 0x01; ++#ifdef SUPPORT_USPD ++ if(ieee->current_network.wmm_info & 0x80) { ++ *tag++ = 0x0f|MAX_SP_Len; ++ } else { ++ *tag++ = MAX_SP_Len; ++ } ++#else ++ *tag++ = MAX_SP_Len; ++#endif ++ *tag_p = tag; ++} ++ ++#ifdef THOMAS_TURBO ++void ieee80211_TURBO_Info(struct ieee80211_device *ieee, u8 **tag_p) { ++ u8 *tag = *tag_p; ++ ++ *tag++ = MFIE_TYPE_GENERIC; //0 ++ *tag++ = 7; ++ *tag++ = 0x00; ++ *tag++ = 0xe0; ++ *tag++ = 0x4c; ++ *tag++ = 0x01;//5 ++ *tag++ = 0x02; ++ *tag++ = 0x11; ++ *tag++ = 0x00; ++ ++ *tag_p = tag; ++ printk(KERN_ALERT "This is enable turbo mode IE process\n"); ++} ++#endif ++ ++void enqueue_mgmt(struct ieee80211_device *ieee, struct sk_buff *skb) ++{ ++ int nh; ++ nh = (ieee->mgmt_queue_head +1) % MGMT_QUEUE_NUM; ++ ++/* ++ * if the queue is full but we have newer frames then ++ * just overwrites the oldest. ++ * ++ * if (nh == ieee->mgmt_queue_tail) ++ * return -1; ++ */ ++ ieee->mgmt_queue_head = nh; ++ ieee->mgmt_queue_ring[nh] = skb; ++ ++ //return 0; ++} ++ ++struct sk_buff *dequeue_mgmt(struct ieee80211_device *ieee) ++{ ++ struct sk_buff *ret; ++ ++ if(ieee->mgmt_queue_tail == ieee->mgmt_queue_head) ++ return NULL; ++ ++ ret = ieee->mgmt_queue_ring[ieee->mgmt_queue_tail]; ++ ++ ieee->mgmt_queue_tail = ++ (ieee->mgmt_queue_tail+1) % MGMT_QUEUE_NUM; ++ ++ return ret; ++} ++ ++void init_mgmt_queue(struct ieee80211_device *ieee) ++{ ++ ieee->mgmt_queue_tail = ieee->mgmt_queue_head = 0; ++} ++ ++ ++void ieee80211_sta_wakeup(struct ieee80211_device *ieee, short nl); ++ ++inline void softmac_mgmt_xmit(struct sk_buff *skb, struct ieee80211_device *ieee) ++{ ++ unsigned long flags; ++ short single = ieee->softmac_features & IEEE_SOFTMAC_SINGLE_QUEUE; ++ struct ieee80211_hdr_3addr *header= ++ (struct ieee80211_hdr_3addr *) skb->data; ++ ++ ++ spin_lock_irqsave(&ieee->lock, flags); ++ ++ /* called with 2nd param 0, no mgmt lock required */ ++ ieee80211_sta_wakeup(ieee,0); ++ ++ if(single){ ++ if(ieee->queue_stop){ ++ ++ enqueue_mgmt(ieee,skb); ++ }else{ ++ header->seq_ctl = cpu_to_le16(ieee->seq_ctrl[0]<<4); ++ ++ if (ieee->seq_ctrl[0] == 0xFFF) ++ ieee->seq_ctrl[0] = 0; ++ else ++ ieee->seq_ctrl[0]++; ++ ++ /* avoid watchdog triggers */ ++ ieee->dev->trans_start = jiffies; ++ ieee->softmac_data_hard_start_xmit(skb,ieee->dev,ieee->basic_rate); ++#if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,0) ++// dev_kfree_skb_any(skb);//edit by thomas //'cause this function will cause Oops called in interrupt context in old version 101907 ++#endif ++ } ++ ++ spin_unlock_irqrestore(&ieee->lock, flags); ++ }else{ ++ spin_unlock_irqrestore(&ieee->lock, flags); ++ spin_lock_irqsave(&ieee->mgmt_tx_lock, flags); ++ ++ header->seq_ctl = cpu_to_le16(ieee->seq_ctrl[0] << 4); ++ ++ if (ieee->seq_ctrl[0] == 0xFFF) ++ ieee->seq_ctrl[0] = 0; ++ else ++ ieee->seq_ctrl[0]++; ++ ++ ieee->softmac_hard_start_xmit(skb,ieee->dev); ++#if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,0) ++// dev_kfree_skb_any(skb);//edit by thomas ++#endif ++ spin_unlock_irqrestore(&ieee->mgmt_tx_lock, flags); ++ } ++} ++ ++ ++inline void softmac_ps_mgmt_xmit(struct sk_buff *skb, struct ieee80211_device *ieee) ++{ ++ ++ short single = ieee->softmac_features & IEEE_SOFTMAC_SINGLE_QUEUE; ++ struct ieee80211_hdr_3addr *header = ++ (struct ieee80211_hdr_3addr *) skb->data; ++ ++ ++ if(single){ ++ ++ header->seq_ctl = cpu_to_le16(ieee->seq_ctrl[0] << 4); ++ ++ if (ieee->seq_ctrl[0] == 0xFFF) ++ ieee->seq_ctrl[0] = 0; ++ else ++ ieee->seq_ctrl[0]++; ++ ++ /* avoid watchdog triggers */ ++ ieee->dev->trans_start = jiffies; ++ ieee->softmac_data_hard_start_xmit(skb,ieee->dev,ieee->basic_rate); ++ ++ }else{ ++ ++ header->seq_ctl = cpu_to_le16(ieee->seq_ctrl[0] << 4); ++ ++ if (ieee->seq_ctrl[0] == 0xFFF) ++ ieee->seq_ctrl[0] = 0; ++ else ++ ieee->seq_ctrl[0]++; ++ ++ ieee->softmac_hard_start_xmit(skb,ieee->dev); ++ ++ } ++ dev_kfree_skb_any(skb);//edit by thomas ++} ++ ++inline struct sk_buff *ieee80211_probe_req(struct ieee80211_device *ieee) ++{ ++ unsigned int len,rate_len; ++ u8 *tag; ++ struct sk_buff *skb; ++ struct ieee80211_probe_request *req; ++ ++#ifdef _RTL8187_EXT_PATCH_ ++ short extMore = 0; ++ if(ieee->ext_patch_ieee80211_probe_req_1) ++ extMore = ieee->ext_patch_ieee80211_probe_req_1(ieee); ++#endif ++ ++ len = ieee->current_network.ssid_len; ++ ++ rate_len = ieee80211_MFIE_rate_len(ieee); ++ ++#ifdef _RTL8187_EXT_PATCH_ ++ if(!extMore) ++#endif ++ skb = dev_alloc_skb(sizeof(struct ieee80211_probe_request) + ++ 2 + len + rate_len); ++#ifdef _RTL8187_EXT_PATCH_ ++ else ++ skb = dev_alloc_skb(sizeof(struct ieee80211_probe_request) + ++ 2 + len + rate_len+128); // MESHID + CAP ++#endif ++ ++ if (!skb) ++ return NULL; ++ ++ req = (struct ieee80211_probe_request *) skb_put(skb,sizeof(struct ieee80211_probe_request)); ++ req->header.frame_ctl = cpu_to_le16(IEEE80211_STYPE_PROBE_REQ); ++ req->header.duration_id = 0; //FIXME: is this OK ? ++ ++ memset(req->header.addr1, 0xff, ETH_ALEN); ++ memcpy(req->header.addr2, ieee->dev->dev_addr, ETH_ALEN); ++ memset(req->header.addr3, 0xff, ETH_ALEN); ++ ++ tag = (u8 *) skb_put(skb,len+2+rate_len); ++ ++ *tag++ = MFIE_TYPE_SSID; ++ *tag++ = len; ++ memcpy(tag, ieee->current_network.ssid, len); ++ tag += len; ++ ++ ieee80211_MFIE_Brate(ieee,&tag); ++ ieee80211_MFIE_Grate(ieee,&tag); ++ ++#ifdef _RTL8187_EXT_PATCH_ ++ if(extMore) ++ ieee->ext_patch_ieee80211_probe_req_2(ieee, skb, tag); ++#endif ++ return skb; ++} ++ ++struct sk_buff *ieee80211_get_beacon_(struct ieee80211_device *ieee); ++ ++#ifdef _RTL8187_EXT_PATCH_ ++#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,20) ++void ext_ieee80211_send_beacon_wq(struct work_struct *work) ++{ ++ struct ieee80211_device *ieee = container_of(work, struct ieee80211_device, ext_send_beacon_wq); ++#else ++void ext_ieee80211_send_beacon_wq(struct ieee80211_device *ieee) ++{ ++#endif ++ ++ struct sk_buff *skb; ++ ++ //unsigned long flags; ++// printk("=========>%s()\n", __FUNCTION__); ++ skb = ieee80211_get_beacon_(ieee); ++ ++ if (skb){ ++ softmac_mgmt_xmit(skb, ieee); ++ ieee->softmac_stats.tx_beacons++; ++ dev_kfree_skb_any(skb);//edit by thomas ++ } ++ ++ ++ //printk(KERN_WARNING "[1] beacon sending!\n"); ++// ieee->beacon_timer.expires = jiffies + ++// (MSECS( ieee->current_network.beacon_interval -5)); ++ ++ //spin_lock_irqsave(&ieee->beacon_lock,flags); ++// if(ieee->beacon_txing) ++// add_timer(&ieee->beacon_timer); ++ //spin_unlock_irqrestore(&ieee->beacon_lock,flags); ++} ++#endif ++ ++void ieee80211_send_beacon(struct ieee80211_device *ieee) ++{ ++ struct sk_buff *skb; ++ ++ //unsigned long flags; ++// printk("=========>%s()\n", __FUNCTION__); ++ skb = ieee80211_get_beacon_(ieee); ++ ++ if (skb){ ++ softmac_mgmt_xmit(skb, ieee); ++ ieee->softmac_stats.tx_beacons++; ++ dev_kfree_skb_any(skb);//edit by thomas ++ } ++ ++ ++ //printk(KERN_WARNING "[1] beacon sending!\n"); ++ ieee->beacon_timer.expires = jiffies + ++ (MSECS( ieee->current_network.beacon_interval -5)); ++ ++ //spin_lock_irqsave(&ieee->beacon_lock,flags); ++ if(ieee->beacon_txing) ++ add_timer(&ieee->beacon_timer); ++ //spin_unlock_irqrestore(&ieee->beacon_lock,flags); ++} ++ ++ ++void ieee80211_send_beacon_cb(unsigned long _ieee) ++{ ++ struct ieee80211_device *ieee = ++ (struct ieee80211_device *) _ieee; ++ unsigned long flags; ++ ++ spin_lock_irqsave(&ieee->beacon_lock, flags); ++ ieee80211_send_beacon(ieee); ++ spin_unlock_irqrestore(&ieee->beacon_lock, flags); ++} ++ ++#ifdef _RTL8187_EXT_PATCH_ ++ ++inline struct sk_buff *ieee80211_probe_req_with_SSID(struct ieee80211_device *ieee, char *ssid, int len_ssid) ++{ ++ unsigned int len,rate_len; ++ u8 *tag; ++ struct sk_buff *skb; ++ struct ieee80211_probe_request *req; ++ ++#ifdef _RTL8187_EXT_PATCH_ ++ short extMore = 0; ++ if(ieee->ext_patch_ieee80211_probe_req_1) ++ extMore = ieee->ext_patch_ieee80211_probe_req_1(ieee); ++#endif ++ ++ len = len_ssid; ++ ++ rate_len = ieee80211_MFIE_rate_len(ieee); ++ ++#ifdef _RTL8187_EXT_PATCH_ ++ if(!extMore) ++#endif ++ skb = dev_alloc_skb(sizeof(struct ieee80211_probe_request) + ++ 2 + len + rate_len); ++#ifdef _RTL8187_EXT_PATCH_ ++ else ++ skb = dev_alloc_skb(sizeof(struct ieee80211_probe_request) + ++ 2 + len + rate_len+128); // MESHID + CAP ++#endif ++ ++ if (!skb) ++ return NULL; ++ ++ req = (struct ieee80211_probe_request *) skb_put(skb,sizeof(struct ieee80211_probe_request)); ++ req->header.frame_ctl = cpu_to_le16(IEEE80211_STYPE_PROBE_REQ); ++ req->header.duration_id = 0; //FIXME: is this OK ? ++ ++ memset(req->header.addr1, 0xff, ETH_ALEN); ++ memcpy(req->header.addr2, ieee->dev->dev_addr, ETH_ALEN); ++ memset(req->header.addr3, 0xff, ETH_ALEN); ++ ++ tag = (u8 *) skb_put(skb,len+2+rate_len); ++ ++ *tag++ = MFIE_TYPE_SSID; ++ *tag++ = len; ++ if(len) ++ { ++ memcpy(tag, ssid, len); ++ tag += len; ++ } ++ ++ ieee80211_MFIE_Brate(ieee,&tag); ++ ieee80211_MFIE_Grate(ieee,&tag); ++ ++#ifdef _RTL8187_EXT_PATCH_ ++ if(extMore) ++ ieee->ext_patch_ieee80211_probe_req_2(ieee, skb, tag); ++#endif ++ return skb; ++} ++ ++#endif // _RTL8187_EXT_PATCH_ ++ ++ ++void ieee80211_send_probe(struct ieee80211_device *ieee) ++{ ++ struct sk_buff *skb; ++ ++#ifdef _RTL8187_EXT_PATCH_ ++ if(ieee->iw_mode == ieee->iw_ext_mode) ++ skb = ieee80211_probe_req_with_SSID(ieee, NULL, 0); ++ else ++#endif ++ skb = ieee80211_probe_req(ieee); ++ if (skb){ ++ softmac_mgmt_xmit(skb, ieee); ++ ieee->softmac_stats.tx_probe_rq++; ++ dev_kfree_skb_any(skb);//edit by thomas ++ } ++} ++ ++void ieee80211_send_probe_requests(struct ieee80211_device *ieee) ++{ ++ if (ieee->active_scan && (ieee->softmac_features & IEEE_SOFTMAC_PROBERQ)){ ++ ieee80211_send_probe(ieee); ++ ieee80211_send_probe(ieee); ++ } ++} ++ ++/* this performs syncro scan blocking the caller until all channels ++ * in the allowed channel map has been checked. ++ */ ++void ieee80211_softmac_scan_syncro(struct ieee80211_device *ieee) ++{ ++ short ch = 0; ++#ifdef ENABLE_DOT11D ++ u8 channel_map[MAX_CHANNEL_NUMBER+1]; ++ memcpy(channel_map, GET_DOT11D_INFO(ieee)->channel_map, MAX_CHANNEL_NUMBER+1); ++#endif ++ ++ ++ down(&ieee->scan_sem); ++ ++ while(1) ++ { ++ ++ do{ ++ ch++; ++ if (ch > MAX_CHANNEL_NUMBER) ++ goto out; /* scan completed */ ++ ++#ifdef ENABLE_DOT11D ++ }while(!channel_map[ch]); ++#else ++ }while(!ieee->channel_map[ch]); ++#endif ++ ++ //printk("=>current channel is %d\n",ch); ++ ++ /* this fuction can be called in two situations ++ * 1- We have switched to ad-hoc mode and we are ++ * performing a complete syncro scan before conclude ++ * there are no interesting cell and to create a ++ * new one. In this case the link state is ++ * IEEE80211_NOLINK until we found an interesting cell. ++ * If so the ieee8021_new_net, called by the RX path ++ * will set the state to IEEE80211_LINKED, so we stop ++ * scanning ++ * 2- We are linked and the root uses run iwlist scan. ++ * So we switch to IEEE80211_LINKED_SCANNING to remember ++ * that we are still logically linked (not interested in ++ * new network events, despite for updating the net list, ++ * but we are temporarly 'unlinked' as the driver shall ++ * not filter RX frames and the channel is changing. ++ * So the only situation in witch are interested is to check ++ * if the state become LINKED because of the #1 situation ++ */ ++ ++ if (ieee->state == IEEE80211_LINKED) ++ goto out; ++ ++ //printk("---->%s: chan %d\n", __func__, ch); ++ ieee->set_chan(ieee->dev, ch); ++#ifdef ENABLE_DOT11D ++ if(channel_map[ch] == 1) ++#endif ++ { ++ ieee80211_send_probe_requests(ieee); ++ } ++ ++ /* this prevent excessive time wait when we ++ * need to wait for a syncro scan to end.. ++ */ ++ if (ieee->sync_scan_hurryup) ++ goto out; ++ ++ ++ msleep_interruptible_rtl(IEEE80211_SOFTMAC_SCAN_TIME); ++ ++ } ++out: ++ ieee->sync_scan_hurryup = 0; ++ up(&ieee->scan_sem); ++#ifdef ENABLE_DOT11D ++ if(IS_DOT11D_ENABLE(ieee)) ++ DOT11D_ScanComplete(ieee); ++#endif ++ ++} ++ ++#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0) ++/* called both by wq with ieee->lock held */ ++void ieee80211_softmac_scan(struct ieee80211_device *ieee) ++{ ++#if 0 ++ short watchdog = 0; ++ do{ ++ ieee->current_network.channel = ++ (ieee->current_network.channel + 1) % MAX_CHANNEL_NUMBER; ++ if (watchdog++ > MAX_CHANNEL_NUMBER) ++ return; /* no good chans */ ++ ++ }while(!ieee->channel_map[ieee->current_network.channel]); ++#endif ++ ++ schedule_task(&ieee->softmac_scan_wq); ++} ++#endif ++ ++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,20)) ++void ieee80211_softmac_scan_wq(struct work_struct *work) ++{ ++ struct delayed_work *dwork = container_of(work, struct delayed_work, work); ++ struct ieee80211_device *ieee = container_of(dwork, struct ieee80211_device, softmac_scan_wq); ++#else ++void ieee80211_softmac_scan_wq(struct ieee80211_device *ieee) ++{ ++#endif ++ //static short watchdog = 0; ++ //short watchdog = 0;//lzm move into ieee->scan_watchdog 081215 for roaming ++ u8 channel_bak = ieee->current_network.channel;//lzm for channel+1 ++#ifdef ENABLE_DOT11D ++ u8 channel_map[MAX_CHANNEL_NUMBER+1]; ++ memcpy(channel_map, GET_DOT11D_INFO(ieee)->channel_map, MAX_CHANNEL_NUMBER+1); ++#endif ++ down(&ieee->scan_sem); ++ ++ do{ ++ ieee->current_network.channel = ++ (ieee->current_network.channel + 1) % MAX_CHANNEL_NUMBER; ++ if (ieee->scan_watchdog++ > MAX_CHANNEL_NUMBER) ++ goto out; /* no good chans */ ++#ifdef ENABLE_DOT11D ++ }while(!channel_map[ieee->current_network.channel]); ++#else ++ }while(!ieee->channel_map[ieee->current_network.channel]); ++#endif ++ ++ if (ieee->scanning == 0 ) ++ goto out; ++ ++ //printk("current channel is %d\n",ieee->current_network.channel); ++ ieee->set_chan(ieee->dev, ieee->current_network.channel); ++#ifdef ENABLE_DOT11D ++ if(channel_map[ieee->current_network.channel] == 1) ++#endif ++ { ++ ieee80211_send_probe_requests(ieee); ++ } ++ ++ ++#if LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0) ++ queue_delayed_work(ieee->wq, &ieee->softmac_scan_wq, IEEE80211_SOFTMAC_SCAN_TIME); ++#else ++ ieee->scan_timer.expires = jiffies + (IEEE80211_SOFTMAC_SCAN_TIME); ++ if (ieee->scanning == 1) ++ add_timer(&ieee->scan_timer); ++#endif ++ ++ up(&ieee->scan_sem); ++ return; ++out: ++ //printk("%s():Stop scan now\n",__FUNCTION__); ++ ieee->actscanning = false; ++ ieee->scan_watchdog = 0; ++ ieee->scanning = 0; ++ ieee->current_network.channel = channel_bak; ++ up(&ieee->scan_sem); ++#ifdef ENABLE_DOT11D ++ if(IS_DOT11D_ENABLE(ieee)) ++ DOT11D_ScanComplete(ieee); ++#endif ++ ++ return; ++} ++ ++#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0) ++void ieee80211_softmac_scan_cb(unsigned long _dev) ++{ ++ unsigned long flags; ++ struct ieee80211_device *ieee = (struct ieee80211_device *)_dev; ++ ++ spin_lock_irqsave(&ieee->lock, flags); ++ ieee80211_softmac_scan(ieee); ++ spin_unlock_irqrestore(&ieee->lock, flags); ++} ++#endif ++ ++ ++void ieee80211_beacons_start(struct ieee80211_device *ieee) ++{ ++ unsigned long flags; ++ ++ spin_lock_irqsave(&ieee->beacon_lock,flags); ++ ++ ieee->beacon_txing = 1; ++ ieee80211_send_beacon(ieee); ++ ++ spin_unlock_irqrestore(&ieee->beacon_lock,flags); ++} ++ ++void ieee80211_beacons_stop(struct ieee80211_device *ieee) ++{ ++ unsigned long flags; ++ ++ spin_lock_irqsave(&ieee->beacon_lock,flags); ++ ++ ieee->beacon_txing = 0; ++ del_timer_sync(&ieee->beacon_timer); ++ ++ spin_unlock_irqrestore(&ieee->beacon_lock,flags); ++ ++} ++ ++ ++void ieee80211_stop_send_beacons(struct ieee80211_device *ieee) ++{ ++ if(ieee->stop_send_beacons) ++ ieee->stop_send_beacons(ieee->dev); ++ if (ieee->softmac_features & IEEE_SOFTMAC_BEACONS) ++ ieee80211_beacons_stop(ieee); ++} ++ ++ ++void ieee80211_start_send_beacons(struct ieee80211_device *ieee) ++{ ++ if(ieee->start_send_beacons) ++ ieee->start_send_beacons(ieee->dev); ++ if(ieee->softmac_features & IEEE_SOFTMAC_BEACONS) ++ ieee80211_beacons_start(ieee); ++} ++ ++ ++void ieee80211_softmac_stop_scan(struct ieee80211_device *ieee) ++{ ++// unsigned long flags; ++ ++ ieee->sync_scan_hurryup = 1; ++ ++ down(&ieee->scan_sem); ++// spin_lock_irqsave(&ieee->lock, flags); ++ ++ if (ieee->scanning == 1){ ++ //printk("%s():Stop scan now\n",__FUNCTION__); ++ ieee->scanning = 0; ++ //lzm add for softmac_scan_wq can't return from out ++ //example: rcv probe_response ++ ieee->scan_watchdog = 0;//lzm add 081215 for roaming ++ ieee->actscanning = false; ++ ++#if LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0) ++ cancel_delayed_work(&ieee->softmac_scan_wq); ++#else ++ del_timer_sync(&ieee->scan_timer); ++#endif ++ } ++ ++// spin_unlock_irqrestore(&ieee->lock, flags); ++ up(&ieee->scan_sem); ++} ++ ++void ieee80211_stop_scan(struct ieee80211_device *ieee) ++{ ++ if (ieee->softmac_features & IEEE_SOFTMAC_SCAN) ++ ieee80211_softmac_stop_scan(ieee); ++ else ++ ieee->stop_scan(ieee->dev); ++} ++ ++/* called with ieee->lock held */ ++void ieee80211_start_scan(struct ieee80211_device *ieee) ++{ ++ ieee->actscanning = true; ++#ifdef CONFIG_IPS ++ ieee->ieee80211_ips_leave(ieee->dev); ++#endif ++ ++#ifdef ENABLE_DOT11D ++ if(IS_DOT11D_ENABLE(ieee) ) ++ { ++ if(IS_COUNTRY_IE_VALID(ieee)) ++ { ++ RESET_CIE_WATCHDOG(ieee); ++ } ++ } ++#endif ++ ++ if (ieee->softmac_features & IEEE_SOFTMAC_SCAN){ ++ if (ieee->scanning == 0){ ++ ieee->scanning = 1; ++#if LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0) ++ queue_delayed_work(ieee->wq, &ieee->softmac_scan_wq,0); ++#else ++ ieee80211_softmac_scan(ieee); ++#endif ++ } ++ }else ++ ieee->start_scan(ieee->dev); ++ ++} ++ ++/* called with wx_sem held */ ++void ieee80211_start_scan_syncro(struct ieee80211_device *ieee) ++{ ++ //printk("====>%s()\n", __func__); ++#ifdef CONFIG_IPS ++ ieee->ieee80211_ips_leave(ieee->dev); ++#endif ++ ieee->actscanning = true; ++ ++#ifdef ENABLE_DOT11D ++ if(IS_DOT11D_ENABLE(ieee) ) ++ { ++ if(IS_COUNTRY_IE_VALID(ieee)) ++ { ++ RESET_CIE_WATCHDOG(ieee); ++ } ++ } ++#endif ++ ++ ieee->sync_scan_hurryup = 0; ++ ++ if (ieee->softmac_features & IEEE_SOFTMAC_SCAN) ++ ieee80211_softmac_scan_syncro(ieee); ++ else ++ ieee->scan_syncro(ieee->dev); ++ ++ ieee->actscanning = false; ++ //printk("<====%s()\n", __func__); ++} ++ ++inline struct sk_buff *ieee80211_authentication_req(struct ieee80211_network *beacon, ++ struct ieee80211_device *ieee, int challengelen) ++{ ++ struct sk_buff *skb; ++ struct ieee80211_authentication *auth; ++ ++ skb = dev_alloc_skb(sizeof(struct ieee80211_authentication) + challengelen); ++ ++ if (!skb) return NULL; ++ ++ auth = (struct ieee80211_authentication *) ++ skb_put(skb, sizeof(struct ieee80211_authentication)); ++ ++ auth->header.frame_ctl = IEEE80211_STYPE_AUTH; ++ if (challengelen) auth->header.frame_ctl |= IEEE80211_FCTL_WEP; ++ ++ auth->header.duration_id = 0x013a; //FIXME ++ ++ memcpy(auth->header.addr1, beacon->bssid, ETH_ALEN); ++ memcpy(auth->header.addr2, ieee->dev->dev_addr, ETH_ALEN); ++ memcpy(auth->header.addr3, beacon->bssid, ETH_ALEN); ++ ++ auth->algorithm = ieee->open_wep ? WLAN_AUTH_OPEN : WLAN_AUTH_SHARED_KEY; ++ ++ auth->transaction = cpu_to_le16(ieee->associate_seq); ++ ieee->associate_seq++; ++ ++ auth->status = cpu_to_le16(WLAN_STATUS_SUCCESS); ++ ++ return skb; ++ ++} ++ ++u8 WPA_OUI[3] = {0x00, 0x50, 0xf2}; ++ ++static struct sk_buff* ieee80211_probe_resp(struct ieee80211_device *ieee, u8 *dest) ++{ ++ u8 *tag; ++ int beacon_size; ++ struct ieee80211_probe_response *beacon_buf; ++ struct sk_buff *skb; ++ int encrypt; ++ int atim_len,erp_len; ++ struct ieee80211_crypt_data* crypt; ++ ++ char *ssid = ieee->current_network.ssid; ++ int ssid_len = ieee->current_network.ssid_len; ++ int rate_len = ieee->current_network.rates_len+2; ++ int rate_ex_len = ieee->current_network.rates_ex_len; ++ ++ int wpa_ie_len = 0, wpa_type=0; ++ if(rate_ex_len > 0) rate_ex_len+=2; ++ ++ if(ieee->current_network.capability & WLAN_CAPABILITY_IBSS) ++ atim_len = 4; ++ else ++ atim_len = 0; ++ ++ if(ieee80211_is_54g(ieee->current_network)) ++ erp_len = 3; ++ else ++ erp_len = 0; ++ if (ieee->wpa_enabled) ++ { ++ // printk("hoho wpa_enalbe\n"); ++ wpa_ie_len = ieee->wpa_ie_len; //24-2 ++ } ++ beacon_size = sizeof(struct ieee80211_probe_response)+ ++ ssid_len ++ +3 //channel ++ +rate_len ++ +rate_ex_len ++ +atim_len ++ +erp_len ++ +wpa_ie_len; ++ ++ skb = dev_alloc_skb(beacon_size); ++ ++ if (!skb) ++ return NULL; ++ ++ beacon_buf = (struct ieee80211_probe_response*) skb_put(skb, beacon_size); ++ ++ memcpy (beacon_buf->header.addr1, dest,ETH_ALEN); ++ memcpy (beacon_buf->header.addr2, ieee->dev->dev_addr, ETH_ALEN); ++ memcpy (beacon_buf->header.addr3, ieee->current_network.bssid, ETH_ALEN); ++ ++ beacon_buf->header.duration_id = 0; //FIXME ++ beacon_buf->beacon_interval = ++ cpu_to_le16(ieee->current_network.beacon_interval); ++ beacon_buf->capability = ++ cpu_to_le16(ieee->current_network.capability & WLAN_CAPABILITY_IBSS); ++ ++ if(ieee->short_slot && (ieee->current_network.capability & WLAN_CAPABILITY_SHORT_SLOT)) ++ cpu_to_le16((beacon_buf->capability |= WLAN_CAPABILITY_SHORT_SLOT)); ++#ifdef _RTL8187_EXT_PATCH_ ++{ ++/* struct ieee80211_crypt_data_list* cryptlist = ieee->cryptlist[1]; ++ u8 i = cryptlist->used; ++ crypt = cryptlist ->crypt[ieee->tx_keyidx]; ++*/ ++ crypt = ieee->cryptlist[0]->crypt[ieee->tx_keyidx]; ++} ++#else ++ ++ crypt = ieee->crypt[ieee->tx_keyidx]; ++#endif ++ if (crypt) ++ wpa_type = strcmp(crypt->ops->name, "TKIP"); ++ ++ ++ encrypt = ieee->host_encrypt && crypt && crypt->ops && ++ ((0 == strcmp(crypt->ops->name, "WEP")||wpa_ie_len)); ++ ++ if (encrypt) ++ beacon_buf->capability |= cpu_to_le16(WLAN_CAPABILITY_PRIVACY); ++ ++ ++ beacon_buf->header.frame_ctl = cpu_to_le16(IEEE80211_STYPE_PROBE_RESP); ++ ++ beacon_buf->info_element.id = MFIE_TYPE_SSID; ++ beacon_buf->info_element.len = ssid_len; ++ ++ tag = (u8*) beacon_buf->info_element.data; ++ ++ memcpy(tag, ssid, ssid_len); ++ ++ tag += ssid_len; ++ ++ *(tag++) = MFIE_TYPE_RATES; ++ *(tag++) = rate_len-2; ++ memcpy(tag,ieee->current_network.rates,rate_len-2); ++ tag+=rate_len-2; ++ ++ *(tag++) = MFIE_TYPE_DS_SET; ++ *(tag++) = 1; ++ *(tag++) = ieee->current_network.channel; ++ ++ if(atim_len){ ++ u16 val16; ++ *(tag++) = MFIE_TYPE_IBSS_SET; ++ *(tag++) = 2; ++ val16 = cpu_to_le16(ieee->current_network.atim_window); ++ //*((u16*)(tag)) = cpu_to_le16(ieee->current_network.atim_window); ++ memcpy((u8 *)tag,(u8 *)&val16,2); ++ tag+=2; ++ } ++ ++ if(erp_len){ ++ *(tag++) = MFIE_TYPE_ERP; ++ *(tag++) = 1; ++ *(tag++) = 0; ++ } ++ ++ if(rate_ex_len){ ++ *(tag++) = MFIE_TYPE_RATES_EX; ++ *(tag++) = rate_ex_len-2; ++ memcpy(tag,ieee->current_network.rates_ex,rate_ex_len-2); ++ tag+=rate_ex_len-2; ++ } ++ if (wpa_ie_len) ++ { ++#if 0 ++ *(tag++) = 0xdd; ++ *(tag++) = wpa_ie_len-2; ++ memcpy(tag, WPA_OUI, 3); ++ tag += 3; ++ *(tag++) = 1; ++ *(tag++) = 1; ++ *(tag++) = 0; ++ ++ memcpy(tag, WPA_OUI, 3); ++ tag += 3; ++ *(tag++) = wpa_type ? 4:2; ++ *(tag++) = 1; ++ *(tag++) = 0; ++ ++ ++ memcpy(tag, WPA_OUI, 3); ++ tag += 3; ++ *(tag++) = wpa_type ? 4:0; ++ *(tag++) = 1; ++ *(tag++) = 0; ++ ++ memcpy(tag, WPA_OUI, 3); ++ tag += 3; ++ *(tag++) = 0; ++#else ++ if (ieee->iw_mode == IW_MODE_ADHOC) ++ {//as Windows will set pairwise key same as the group key which is not allowed in Linux, so set this for IOT issue. WB 2008.07.07 ++ memcpy(&ieee->wpa_ie[14], &ieee->wpa_ie[8], 4); ++ } ++ ++ memcpy(tag, ieee->wpa_ie, ieee->wpa_ie_len); ++ ++#endif ++ } ++ ++ ++ skb->dev = ieee->dev; ++ return skb; ++} ++ ++ ++#ifdef _RTL8187_EXT_PATCH_ ++struct sk_buff* ieee80211_ext_probe_resp_by_net(struct ieee80211_device *ieee, u8 *dest, struct ieee80211_network *net) ++{ ++ u8 *tag; ++ int beacon_size; ++ struct ieee80211_probe_response *beacon_buf; ++ struct sk_buff *skb; ++ int encrypt; ++ int atim_len,erp_len; ++ struct ieee80211_crypt_data* crypt; ++ u8 broadcast_addr[] = {0xff,0xff,0xff,0xff,0xff,0xff}; ++ ++ char *ssid = net->ssid; ++ int ssid_len = net->ssid_len; ++ ++ int rate_len = ieee->current_network.rates_len+2; ++ int rate_ex_len = ieee->current_network.rates_ex_len; ++ int wpa_ie_len = 0, wpa_type=0; ++ if(rate_ex_len > 0) rate_ex_len+=2; ++ ++ if( ieee->meshScanMode&4) ++ ieee->current_network.channel = ieee->ext_patch_ieee80211_ext_stop_scan_wq_set_channel(ieee); ++ if( ieee->meshScanMode&6) ++ { ++ ++#if LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0) ++ queue_work(ieee->wq, &ieee->ext_stop_scan_wq); ++#else ++ schedule_task(&ieee->ext_stop_scan_wq); ++#endif ++ } ++ if(ieee->current_network.capability & WLAN_CAPABILITY_IBSS) // use current_network here ++ atim_len = 4; ++ else ++ atim_len = 0; ++ ++ if(ieee80211_is_54g(*net)) ++ erp_len = 3; ++ else ++ erp_len = 0; ++ ++ if (ieee->wpa_enabled &&(ieee->iw_ext_mode==ieee->iw_mode)) ++ { ++// printk("hoho wpa_enalbe\n"); ++ wpa_ie_len = ieee->wpa_ie_len; //24-2 ++ } ++ ++ beacon_size = sizeof(struct ieee80211_probe_response)+ ++ ssid_len ++ +3 //channel ++ +rate_len ++ +rate_ex_len ++ +atim_len ++ +erp_len ++ +wpa_ie_len; ++//b ++ skb = dev_alloc_skb(beacon_size+196); ++ ++ if (!skb) ++ return NULL; ++ ++ beacon_buf = (struct ieee80211_probe_response*) skb_put(skb, beacon_size); ++ ++ memcpy (beacon_buf->header.addr1, dest,ETH_ALEN); ++ memcpy (beacon_buf->header.addr2, ieee->dev->dev_addr, ETH_ALEN); ++ memcpy (beacon_buf->header.addr3, ieee->current_network.bssid, ETH_ALEN); ++ ++ beacon_buf->header.duration_id = 0; //FIXME ++ ++ beacon_buf->beacon_interval = ++ cpu_to_le16(ieee->current_network.beacon_interval); // use current_network here ++ beacon_buf->capability = ++ cpu_to_le16(ieee->current_network.capability & WLAN_CAPABILITY_IBSS); ++ ++ if(ieee->short_slot && (ieee->current_network.capability & WLAN_CAPABILITY_SHORT_SLOT)) ++ cpu_to_le16((beacon_buf->capability |= WLAN_CAPABILITY_SHORT_SLOT)); ++#ifdef _RTL8187_EXT_PATCH_ ++ ++ crypt = ieee->cryptlist[0]->crypt[ieee->tx_keyidx]; ++#else ++ ++ crypt = ieee->crypt[ieee->tx_keyidx]; ++#endif ++ ++// crypt = ieee->crypt[ieee->tx_keyidx]; ++ if (crypt) ++ wpa_type = strcmp(crypt->ops->name, "TKIP"); ++ ++ encrypt = ieee->host_encrypt && crypt && crypt->ops && ++ ((0 == strcmp(crypt->ops->name, "WEP")||wpa_ie_len)); ++ ++ if (encrypt) ++ beacon_buf->capability |= cpu_to_le16(WLAN_CAPABILITY_PRIVACY); ++ ++ ++ beacon_buf->header.frame_ctl = cpu_to_le16(IEEE80211_STYPE_PROBE_RESP); ++ ++ beacon_buf->info_element.id = MFIE_TYPE_SSID; ++ beacon_buf->info_element.len = ssid_len; ++ ++ tag = (u8*) beacon_buf->info_element.data; ++ ++ // brocad cast / probe rsp ++ if(memcmp(dest, broadcast_addr, ETH_ALEN )) ++ memcpy(tag, ssid, ssid_len); ++ else ++ ssid_len=0; ++ ++ tag += ssid_len; ++ ++//get_bssrate_set(priv, _SUPPORTEDRATES_IE_, &pbssrate, &bssrate_len); ++//pbuf = set_ie(pbuf, _SUPPORTEDRATES_IE_, bssrate_len, pbssrate, &frlen); ++ ++ *(tag++) = MFIE_TYPE_RATES; ++ *(tag++) = rate_len-2; ++ memcpy(tag,ieee->current_network.rates,rate_len-2); ++ tag+=rate_len-2; ++ ++ *(tag++) = MFIE_TYPE_DS_SET; ++ *(tag++) = 1; ++ *(tag++) = ieee->current_network.channel; // use current_network here ++ ++ ++ if(atim_len){ ++ *(tag++) = MFIE_TYPE_IBSS_SET; ++ *(tag++) = 2; ++ *((u16*)(tag)) = cpu_to_le16(ieee->current_network.atim_window); // use current_network here ++ tag+=2; ++ } ++ ++ if(erp_len){ ++ *(tag++) = MFIE_TYPE_ERP; ++ *(tag++) = 1; ++ *(tag++) = 0; ++ } ++ ++ if(rate_ex_len){ ++ *(tag++) = MFIE_TYPE_RATES_EX; ++ *(tag++) = rate_ex_len-2; ++ memcpy(tag,ieee->current_network.rates_ex,rate_ex_len-2); ++ tag+=rate_ex_len-2; ++ } ++ ++ if (wpa_ie_len) ++ { ++#if 0 ++ *(tag++) = 0xdd; ++ *(tag++) = wpa_ie_len-2; ++ memcpy(tag, WPA_OUI, 3); ++ tag += 3; ++ *(tag++) = 1; ++ *(tag++) = 1; ++ *(tag++) = 0; ++ ++ memcpy(tag, WPA_OUI, 3); ++ tag += 3; ++ *(tag++) = wpa_type ? 4:2; ++ *(tag++) = 1; ++ *(tag++) = 0; ++ ++ ++ memcpy(tag, WPA_OUI, 3); ++ tag += 3; ++ *(tag++) = wpa_type ? 4:0; ++ *(tag++) = 1; ++ *(tag++) = 0; ++ ++ memcpy(tag, WPA_OUI, 3); ++ tag += 3; ++ *(tag++) = 0; ++#else ++ memcpy(tag, ieee->wpa_ie, ieee->wpa_ie_len); ++#endif ++ } ++ ++ ++ skb->dev = ieee->dev; ++ return skb; ++} ++#endif // _RTL8187_EXT_PATCH_ ++ ++ ++struct sk_buff* ieee80211_assoc_resp(struct ieee80211_device *ieee, u8 *dest) ++{ ++ struct sk_buff *skb; ++ u8* tag; ++ ++ struct ieee80211_crypt_data* crypt; ++ struct ieee80211_assoc_response_frame *assoc; ++ short encrypt; ++ ++ unsigned int rate_len = ieee80211_MFIE_rate_len(ieee); ++ int len = sizeof(struct ieee80211_assoc_response_frame) + rate_len; ++ ++ skb = dev_alloc_skb(len); ++ ++ if (!skb) ++ return NULL; ++ ++ assoc = (struct ieee80211_assoc_response_frame *) ++ skb_put(skb,sizeof(struct ieee80211_assoc_response_frame)); ++ ++ assoc->header.frame_ctl = cpu_to_le16(IEEE80211_STYPE_ASSOC_RESP); ++ memcpy(assoc->header.addr1, dest,ETH_ALEN); ++ memcpy(assoc->header.addr3, ieee->dev->dev_addr, ETH_ALEN); ++ memcpy(assoc->header.addr2, ieee->dev->dev_addr, ETH_ALEN); ++ assoc->capability = cpu_to_le16(ieee->iw_mode == IW_MODE_MASTER ? ++ WLAN_CAPABILITY_BSS : WLAN_CAPABILITY_IBSS); ++ ++ ++ if(ieee->short_slot) ++ assoc->capability |= cpu_to_le16(WLAN_CAPABILITY_SHORT_SLOT); ++ ++ if (ieee->host_encrypt){ ++#ifdef _RTL8187_EXT_PATCH_ ++ crypt = ieee->cryptlist[0]->crypt[ieee->tx_keyidx]; ++#else ++ crypt = ieee->crypt[ieee->tx_keyidx]; ++#endif ++ } ++ else crypt = NULL; ++ ++ encrypt = ( crypt && crypt->ops); ++ ++ if (encrypt) ++ assoc->capability |= cpu_to_le16(WLAN_CAPABILITY_PRIVACY); ++ ++ assoc->status = 0; ++ assoc->aid = cpu_to_le16(ieee->assoc_id); ++ if (ieee->assoc_id == 0x2007) ieee->assoc_id=0; ++ else ieee->assoc_id++; ++ ++ tag = (u8*) skb_put(skb, rate_len); ++ ++ ieee80211_MFIE_Brate(ieee, &tag); ++ ieee80211_MFIE_Grate(ieee, &tag); ++ ++ return skb; ++} ++ ++struct sk_buff* ieee80211_auth_resp(struct ieee80211_device *ieee,int status, u8 *dest) ++{ ++ struct sk_buff *skb; ++ struct ieee80211_authentication *auth; ++ ++ skb = dev_alloc_skb(sizeof(struct ieee80211_authentication)+1); ++ ++ if (!skb) ++ return NULL; ++ ++ skb->len = sizeof(struct ieee80211_authentication); ++ ++ auth = (struct ieee80211_authentication *)skb->data; ++ ++ auth->status = cpu_to_le16(status); ++ auth->transaction = cpu_to_le16(2); ++ auth->algorithm = cpu_to_le16(WLAN_AUTH_OPEN); ++ ++#ifdef _RTL8187_EXT_PATCH_ ++ if(ieee->iw_mode == ieee->iw_ext_mode) ++ memcpy(auth->header.addr3, dest, ETH_ALEN); ++#else ++ memcpy(auth->header.addr3, ieee->dev->dev_addr, ETH_ALEN); ++#endif ++ memcpy(auth->header.addr2, ieee->dev->dev_addr, ETH_ALEN); ++ memcpy(auth->header.addr1, dest, ETH_ALEN); ++ auth->header.frame_ctl = cpu_to_le16(IEEE80211_STYPE_AUTH); ++ return skb; ++ ++ ++} ++ ++struct sk_buff* ieee80211_null_func(struct ieee80211_device *ieee,short pwr) ++{ ++ struct sk_buff *skb; ++ struct ieee80211_hdr_3addr* hdr; ++ ++ skb = dev_alloc_skb(sizeof(struct ieee80211_hdr_3addr)); ++ ++ if (!skb) ++ return NULL; ++ ++ hdr = (struct ieee80211_hdr_3addr*)skb_put(skb,sizeof(struct ieee80211_hdr_3addr)); ++ ++ memcpy(hdr->addr1, ieee->current_network.bssid, ETH_ALEN); ++ memcpy(hdr->addr2, ieee->dev->dev_addr, ETH_ALEN); ++ memcpy(hdr->addr3, ieee->current_network.bssid, ETH_ALEN); ++ ++ hdr->frame_ctl = cpu_to_le16(IEEE80211_FTYPE_DATA | ++ IEEE80211_STYPE_NULLFUNC | IEEE80211_FCTL_TODS | ++ (pwr ? IEEE80211_FCTL_PM:0)); ++ ++ return skb; ++ ++ ++} ++ ++ ++void ieee80211_resp_to_assoc_rq(struct ieee80211_device *ieee, u8* dest) ++{ ++ struct sk_buff *buf = ieee80211_assoc_resp(ieee, dest); ++ ++ if (buf){ ++ softmac_mgmt_xmit(buf, ieee); ++ dev_kfree_skb_any(buf);//edit by thomas ++ } ++} ++ ++ ++void ieee80211_resp_to_auth(struct ieee80211_device *ieee, int s, u8* dest) ++{ ++ struct sk_buff *buf = ieee80211_auth_resp(ieee, s, dest); ++ ++ if (buf){ ++ softmac_mgmt_xmit(buf, ieee); ++ dev_kfree_skb_any(buf);//edit by thomas ++ } ++} ++ ++ ++void ieee80211_resp_to_probe(struct ieee80211_device *ieee, u8 *dest) ++{ ++ ++ struct sk_buff *buf = ieee80211_probe_resp(ieee, dest); ++ ++ if (buf) { ++ softmac_mgmt_xmit(buf, ieee); ++ dev_kfree_skb_any(buf);//edit by thomas ++ } ++} ++ ++ ++inline struct sk_buff *ieee80211_association_req(struct ieee80211_network *beacon,struct ieee80211_device *ieee) ++{ ++ struct sk_buff *skb; ++ ++ struct ieee80211_assoc_request_frame *hdr; ++ u8 *tag; ++ //int i; ++ unsigned int wpa_len = beacon->wpa_ie_len; ++#if 1 ++ // for testing purpose ++ unsigned int rsn_len = beacon->rsn_ie_len; ++#else ++ unsigned int rsn_len = beacon->rsn_ie_len - 4; ++#endif ++ unsigned int rate_len = ieee80211_MFIE_rate_len(ieee); ++ unsigned int wmm_info_len = beacon->QoS_Enable?9:0; ++#ifdef THOMAS_TURBO ++ unsigned int turbo_info_len = beacon->Turbo_Enable?9:0; ++#endif ++ ++ u8 encry_proto = ieee->wpax_type_notify & 0xff; ++ ++ ++ int len = 0; ++ ++ //[0] Notify type of encryption: WPA/WPA2 ++ //[1] pair wise type ++ //[2] authen type ++ if(ieee->wpax_type_set) { ++ if (IEEE_PROTO_WPA == encry_proto) { ++ rsn_len = 0; ++ } else if (IEEE_PROTO_RSN == encry_proto) { ++ wpa_len = 0; ++ } ++ } ++#ifdef THOMAS_TURBO ++ len = sizeof(struct ieee80211_assoc_request_frame)+ ++ + beacon->ssid_len//essid tagged val ++ + rate_len//rates tagged val ++ + wpa_len ++ + rsn_len ++ + wmm_info_len ++ + turbo_info_len; ++#else ++ len = sizeof(struct ieee80211_assoc_request_frame)+ ++ + beacon->ssid_len//essid tagged val ++ + rate_len//rates tagged val ++ + wpa_len ++ + rsn_len ++ + wmm_info_len; ++#endif ++ ++#ifdef _RTL8187_EXT_PATCH_ ++ if(ieee->iw_mode == ieee->iw_ext_mode) ++ skb = dev_alloc_skb(len+256); // stanley ++ else ++#endif ++ skb = dev_alloc_skb(len); ++ ++ if (!skb) ++ return NULL; ++ ++ hdr = (struct ieee80211_assoc_request_frame *) ++ skb_put(skb, sizeof(struct ieee80211_assoc_request_frame)); ++ ++ ++ hdr->header.frame_ctl = IEEE80211_STYPE_ASSOC_REQ; ++ hdr->header.duration_id= 37; //FIXME ++ memcpy(hdr->header.addr1, beacon->bssid, ETH_ALEN); ++ memcpy(hdr->header.addr2, ieee->dev->dev_addr, ETH_ALEN); ++ memcpy(hdr->header.addr3, beacon->bssid, ETH_ALEN); ++ memcpy(ieee->ap_mac_addr, beacon->bssid, ETH_ALEN);//for HW security, John ++ ++ hdr->capability = cpu_to_le16(WLAN_CAPABILITY_BSS); ++ if (beacon->capability & WLAN_CAPABILITY_PRIVACY ) ++ hdr->capability |= cpu_to_le16(WLAN_CAPABILITY_PRIVACY); ++ ++ if (beacon->capability & WLAN_CAPABILITY_SHORT_PREAMBLE ) ++ hdr->capability |= cpu_to_le16(WLAN_CAPABILITY_SHORT_PREAMBLE); ++ ++ if(ieee->short_slot) ++ hdr->capability |= cpu_to_le16(WLAN_CAPABILITY_SHORT_SLOT); ++ ++#ifdef _RTL8187_EXT_PATCH_ ++ if((ieee->iw_mode == ieee->iw_ext_mode) && ieee->ext_patch_ieee80211_association_req_1) ++ ieee->ext_patch_ieee80211_association_req_1(hdr); ++#endif ++ ++ hdr->listen_interval = 0xa; //FIXME ++ ++ hdr->info_element.id = MFIE_TYPE_SSID; ++ ++ hdr->info_element.len = beacon->ssid_len; ++ tag = skb_put(skb, beacon->ssid_len); ++ memcpy(tag, beacon->ssid, beacon->ssid_len); ++ ++ tag = skb_put(skb, rate_len); ++ ++ ieee80211_MFIE_Brate(ieee, &tag); ++ ieee80211_MFIE_Grate(ieee, &tag); ++ ++ //add rsn==0 condition for ap's mix security mode(wpa+wpa2), john2007.8.9 ++ //choose AES encryption as default algorithm while using mixed mode ++#if 0 ++ if(rsn_len == 0){ ++ ++ tag = skb_put(skb,wpa_len); ++ ++ if(wpa_len) { ++ ++ ++ //{add by david. 2006.8.31 ++ //fix linksys compatibility bug ++ //} ++ if(wpa_len > 24) {//22+2, mean include the capability ++ beacon->wpa_ie[wpa_len - 2] = 0; ++ } ++ //multicast cipher OUI ++ if( beacon->wpa_ie[11]==0x2 ){ //0x0050f202 is the oui of tkip ++ ieee->broadcast_key_type = KEY_TYPE_TKIP; ++ } ++ else if( beacon->wpa_ie[11]==0x4 ){//0x0050f204 is the oui of ccmp ++ ieee->broadcast_key_type = KEY_TYPE_CCMP; ++ } ++ //unicast cipher OUI ++ if( beacon->wpa_ie[14]==0 ++ && beacon->wpa_ie[15]==0x50 ++ && beacon->wpa_ie[16]==0xf2 ++ && beacon->wpa_ie[17]==0x2 ){ //0x0050f202 is the oui of tkip ++ ieee->pairwise_key_type = KEY_TYPE_TKIP; ++ } ++ ++ else if( beacon->wpa_ie[14]==0 ++ && beacon->wpa_ie[15]==0x50 ++ && beacon->wpa_ie[16]==0xf2 ++ && beacon->wpa_ie[17]==0x4 ){//0x0050f204 is the oui of ccmp ++ ieee->pairwise_key_type = KEY_TYPE_CCMP; ++ } ++ //indicate the wpa_ie content to WPA_SUPPLICANT ++ buff = kmalloc(IW_CUSTOM_MAX, GFP_ATOMIC); ++ memset(buff, 0, IW_CUSTOM_MAX); ++ p=buff; ++ p += sprintf(p, "ASSOCINFO(ReqIEs="); ++ for(i=0;i<wpa_len;i++){ ++ p += sprintf(p, "%02x", beacon->wpa_ie[i]); ++ } ++ p += sprintf(p, ")"); ++ memset(&wrqu, 0, sizeof(wrqu) ); ++ wrqu.data.length = p - buff; ++ ++ wireless_send_event(dev, IWEVCUSTOM, &wrqu, buff); ++ memcpy(tag,beacon->wpa_ie,wpa_len); ++ } ++ ++ } ++ ++ if(rsn_len > 22) { ++ ++ if( beacon->rsn_ie[4]==0x0 && ++ beacon->rsn_ie[5]==0xf && ++ beacon->rsn_ie[6]==0xac){ ++ ++ switch(beacon->rsn_ie[7]){ ++ case 0x1: ++ ieee->broadcast_key_type = KEY_TYPE_WEP40; ++ break; ++ case 0x2: ++ ieee->broadcast_key_type = KEY_TYPE_TKIP; ++ break; ++ case 0x4: ++ ieee->broadcast_key_type = KEY_TYPE_CCMP; ++ break; ++ case 0x5: ++ ieee->broadcast_key_type = KEY_TYPE_WEP104; ++ break; ++ default: ++ printk("fault suite type in RSN broadcast key\n"); ++ break; ++ } ++ } ++ ++ if( beacon->rsn_ie[10]==0x0 && ++ beacon->rsn_ie[11]==0xf && ++ beacon->rsn_ie[12]==0xac){ ++ if(beacon->rsn_ie[8]==1){//not mixed mode ++ switch(beacon->rsn_ie[13]){ ++ case 0x2: ++ ieee->pairwise_key_type = KEY_TYPE_TKIP; ++ break; ++ case 0x4: ++ ieee->pairwise_key_type = KEY_TYPE_CCMP; ++ break; ++ default: ++ printk("fault suite type in RSN pairwise key\n"); ++ break; ++ } ++ } ++ else if(beacon->rsn_ie[8]==2){//mixed mode ++ ieee->pairwise_key_type = KEY_TYPE_CCMP; ++ } ++ } ++ ++ ++ ++ tag = skb_put(skb,22); ++ memcpy(tag,(beacon->rsn_ie + info_addr),8); ++ tag[1] = 20; ++ tag += 8; ++ info_addr += 8; ++ ++ spin_lock_irqsave(&ieee->wpax_suitlist_lock,flags); ++ for (i = 0; i < 2; i++) { ++ tag[0] = 1; ++ tag[1] = 0; ++ tag += 2; ++ suite_count = beacon->rsn_ie[info_addr] + \ ++ (beacon->rsn_ie[info_addr + 1] << 8); ++ info_addr += 2; ++ if(1 == suite_count) { ++ memcpy(tag,(beacon->rsn_ie + info_addr),4); ++ info_addr += 4; ++ } else { ++ // if the wpax_type_notify has been set by the application, ++ // just use it, otherwise just use the default one. ++ if(ieee->wpax_type_set) { ++ suit_select = ((0 == i) ? pairwise_type:authen_type)&0x0f ; ++ memcpy(tag,rsn_authen_cipher_suite[suit_select],4); ++ } else { ++ //default set as ccmp, or none authentication ++ if(i == 0) { ++ memcpy(tag,rsn_authen_cipher_suite[4],4); ++ } else { ++ memcpy(tag,rsn_authen_cipher_suite[2],4); ++ } ++ ++ } ++ ++ info_addr += (suite_count * 4); ++ } ++ tag += 4; ++ } ++ spin_unlock_irqrestore(&ieee->wpax_suitlist_lock,flags); ++ ++ tag[0] = 0; ++ tag[1] = beacon->rsn_ie[info_addr+1]; ++ ++ ++ ++ } else { ++ tag = skb_put(skb,rsn_len); ++ if(rsn_len) { ++ ++ ++ if( beacon->rsn_ie[4]==0x0 && ++ beacon->rsn_ie[5]==0xf && ++ beacon->rsn_ie[6]==0xac){ ++ switch(beacon->rsn_ie[7]){ ++ case 0x1: ++ ieee->broadcast_key_type = KEY_TYPE_WEP40; ++ break; ++ case 0x2: ++ ieee->broadcast_key_type = KEY_TYPE_TKIP; ++ break; ++ case 0x4: ++ ieee->broadcast_key_type = KEY_TYPE_CCMP; ++ break; ++ case 0x5: ++ ieee->broadcast_key_type = KEY_TYPE_WEP104; ++ break; ++ default: ++ printk("fault suite type in RSN broadcast key\n"); ++ break; ++ } ++ } ++ if( beacon->rsn_ie[10]==0x0 && ++ beacon->rsn_ie[11]==0xf && ++ beacon->rsn_ie[12]==0xac){ ++ if(beacon->rsn_ie[8]==1){//not mixed mode ++ switch(beacon->rsn_ie[13]){ ++ case 0x2: ++ ieee->pairwise_key_type = KEY_TYPE_TKIP; ++ break; ++ case 0x4: ++ ieee->pairwise_key_type = KEY_TYPE_CCMP; ++ break; ++ default: ++ printk("fault suite type in RSN pairwise key\n"); ++ break; ++ } ++ ++ } ++ else if(beacon->rsn_ie[8]==2){//mixed mode ++ ieee->pairwise_key_type = KEY_TYPE_CCMP; ++ } ++ } ++ ++ ++ beacon->rsn_ie[rsn_len - 2] = 0; ++ memcpy(tag,beacon->rsn_ie,rsn_len); ++ } ++ } ++#else ++ if (ieee->wpa_ie){ ++ tag = skb_put(skb,ieee->wpa_ie_len); ++ memcpy(tag,ieee->wpa_ie,ieee->wpa_ie_len); ++ } ++#endif ++ tag = skb_put(skb,wmm_info_len); ++ if(wmm_info_len) { ++ ieee80211_WMM_Info(ieee, &tag); ++ } ++#ifdef THOMAS_TURBO ++ tag = skb_put(skb,turbo_info_len); ++ if(turbo_info_len) { ++ ieee80211_TURBO_Info(ieee, &tag); ++ } ++#endif ++ ++#ifdef _RTL8187_EXT_PATCH_ ++ if((ieee->iw_mode == ieee->iw_ext_mode) && ieee->ext_patch_ieee80211_association_req_2) ++ ieee->ext_patch_ieee80211_association_req_2(ieee, beacon, skb); ++#endif ++ ++ return skb; ++} ++ ++void ieee80211_associate_abort(struct ieee80211_device *ieee) ++{ ++ ++ unsigned long flags; ++ spin_lock_irqsave(&ieee->lock, flags); ++ ++ ieee->associate_seq++; ++ ++ /* don't scan, and avoid to have the RX path possibily ++ * try again to associate. Even do not react to AUTH or ++ * ASSOC response. Just wait for the retry wq to be scheduled. ++ * Here we will check if there are good nets to associate ++ * with, so we retry or just get back to NO_LINK and scanning ++ */ ++ if (ieee->state == IEEE80211_ASSOCIATING_AUTHENTICATING){ ++ IEEE80211_DEBUG_MGMT("Authentication failed\n"); ++ ieee->softmac_stats.no_auth_rs++; ++ }else{ ++ IEEE80211_DEBUG_MGMT("Association failed\n"); ++ ieee->softmac_stats.no_ass_rs++; ++ } ++ ++ ieee->state = IEEE80211_ASSOCIATING_RETRY; ++ ++#if LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0) ++ queue_delayed_work(ieee->wq, &ieee->associate_retry_wq, \ ++ IEEE80211_SOFTMAC_ASSOC_RETRY_TIME); ++#else ++ schedule_task(&ieee->associate_retry_wq); ++#endif ++ ++ spin_unlock_irqrestore(&ieee->lock, flags); ++} ++ ++void ieee80211_associate_abort_cb(unsigned long dev) ++{ ++ ieee80211_associate_abort((struct ieee80211_device *) dev); ++} ++ ++ ++void ieee80211_associate_step1(struct ieee80211_device *ieee) ++{ ++ struct ieee80211_network *beacon = &ieee->current_network; ++ struct sk_buff *skb; ++ ++ IEEE80211_DEBUG_MGMT("Stopping scan\n"); ++ ++ ieee->softmac_stats.tx_auth_rq++; ++ skb=ieee80211_authentication_req(beacon, ieee, 0); ++ ++#ifdef _RTL8187_EXT_PATCH_ ++ if(ieee->iw_mode == ieee->iw_ext_mode ) { ++ if(skb) ++ softmac_mgmt_xmit(skb, ieee); ++ return; ++ }else ++#endif ++ if (!skb) ++ ieee80211_associate_abort(ieee); ++ else{ ++ ieee->state = IEEE80211_ASSOCIATING_AUTHENTICATING ; ++ IEEE80211_DEBUG_MGMT("Sending authentication request\n"); ++ //printk(KERN_WARNING "Sending authentication request\n"); ++ softmac_mgmt_xmit(skb, ieee); ++ //BUGON when you try to add_timer twice, using mod_timer may be better, john0709 ++ if(!timer_pending(&ieee->associate_timer)){ ++ ieee->associate_timer.expires = jiffies + (HZ / 2); ++ add_timer(&ieee->associate_timer); ++ } ++ dev_kfree_skb_any(skb);//edit by thomas ++ } ++} ++ ++void ieee80211_auth_challenge(struct ieee80211_device *ieee, u8 *challenge, int chlen) ++{ ++ u8 *c; ++ struct sk_buff *skb; ++ struct ieee80211_network *beacon = &ieee->current_network; ++// int hlen = sizeof(struct ieee80211_authentication); ++ ++ ieee->associate_seq++; ++ ieee->softmac_stats.tx_auth_rq++; ++ ++ skb = ieee80211_authentication_req(beacon, ieee, chlen+2); ++ if (!skb) ++ ieee80211_associate_abort(ieee); ++ else{ ++ c = skb_put(skb, chlen+2); ++ *(c++) = MFIE_TYPE_CHALLENGE; ++ *(c++) = chlen; ++ memcpy(c, challenge, chlen); ++ ++ IEEE80211_DEBUG_MGMT("Sending authentication challenge response\n"); ++ ++ ieee80211_encrypt_fragment(ieee, skb, sizeof(struct ieee80211_hdr_3addr )); ++ ++ softmac_mgmt_xmit(skb, ieee); ++ ++ if(!timer_pending(&ieee->associate_timer)){ ++ ieee->associate_timer.expires = jiffies + (HZ / 2); ++ add_timer(&ieee->associate_timer); ++ } ++ dev_kfree_skb_any(skb);//edit by thomas ++ } ++ kfree(challenge); ++} ++ ++#ifdef _RTL8187_EXT_PATCH_ ++ ++// based on ieee80211_assoc_resp ++struct sk_buff* ieee80211_assoc_resp_by_net(struct ieee80211_device *ieee, u8 *dest, unsigned short status, struct ieee80211_network *pstat, int pkt_type) ++{ ++ struct sk_buff *skb; ++ u8* tag; ++ ++ struct ieee80211_crypt_data* crypt; ++ struct ieee80211_assoc_response_frame *assoc; ++ short encrypt; ++ ++ unsigned int rate_len = ieee80211_MFIE_rate_len(ieee); ++ int len = sizeof(struct ieee80211_assoc_response_frame) + rate_len; ++ ++ if(ieee->iw_mode == ieee->iw_ext_mode) ++ skb = dev_alloc_skb(len+256); // stanley ++ else ++ skb = dev_alloc_skb(len); ++ ++ if (!skb) ++ return NULL; ++ ++ assoc = (struct ieee80211_assoc_response_frame *) ++ skb_put(skb,sizeof(struct ieee80211_assoc_response_frame)); ++ ++ assoc->header.frame_ctl = cpu_to_le16(pkt_type); ++ ++ memcpy(assoc->header.addr1, dest,ETH_ALEN); ++ memcpy(assoc->header.addr3, ieee->dev->dev_addr, ETH_ALEN); ++ memcpy(assoc->header.addr2, ieee->dev->dev_addr, ETH_ALEN); ++ assoc->capability = cpu_to_le16(ieee->iw_mode == IW_MODE_MASTER ? ++ WLAN_CAPABILITY_BSS : WLAN_CAPABILITY_IBSS); ++ ++ if((ieee->iw_mode == ieee->iw_ext_mode) && ieee->ext_patch_ieee80211_assoc_resp_by_net_1) ++ ieee->ext_patch_ieee80211_assoc_resp_by_net_1(assoc); ++ ++ if(ieee->short_slot) ++ assoc->capability |= cpu_to_le16(WLAN_CAPABILITY_SHORT_SLOT); ++ ++ if (ieee->host_encrypt) ++#ifdef _RTL8187_EXT_PATCH_ ++ crypt = ieee->cryptlist[0]->crypt[ieee->tx_keyidx]; ++#else ++ crypt = ieee->crypt[ieee->tx_keyidx]; ++#endif ++ ++ else crypt = NULL; ++ ++ encrypt = ( crypt && crypt->ops); ++ ++ if (encrypt) ++ assoc->capability |= cpu_to_le16(WLAN_CAPABILITY_PRIVACY); ++ ++ assoc->status = 0; ++ assoc->aid = cpu_to_le16(ieee->assoc_id); ++ if (ieee->assoc_id == 0x2007) ieee->assoc_id=0; ++ else ieee->assoc_id++; ++ ++ assoc->info_element.id = 230; // Stanley, an unused id (just a hot fix) ++ assoc->info_element.len = 0; ++ ++ tag = (u8*) skb_put(skb, rate_len); ++ ++ ieee80211_MFIE_Brate(ieee, &tag); ++ ieee80211_MFIE_Grate(ieee, &tag); ++ ++ if((ieee->iw_mode == ieee->iw_ext_mode) && ieee->ext_patch_ieee80211_assoc_resp_by_net_2) ++ ieee->ext_patch_ieee80211_assoc_resp_by_net_2(ieee, pstat, pkt_type, skb); ++ ++ return skb; ++} ++ ++// based on ieee80211_resp_to_assoc_rq ++void ieee80211_ext_issue_assoc_rsp(struct ieee80211_device *ieee, u8 *dest, unsigned short status, struct ieee80211_network *pstat, int pkt_type) ++{ ++ struct sk_buff *buf = ieee80211_assoc_resp_by_net(ieee, dest, status, pstat, pkt_type); ++ ++ if (buf) ++ softmac_mgmt_xmit(buf, ieee); ++} ++ ++// based on ieee80211_associate_step2 ++void ieee80211_ext_issue_assoc_req(struct ieee80211_device *ieee, struct ieee80211_network *pstat) ++{ ++ ++ struct sk_buff* skb; ++ ++ // printk("@@@@@ ieee80211_ext_issue_assoc_req on channel: %d\n", ieee->current_network.channel); ++ ++ ieee->softmac_stats.tx_ass_rq++; ++ skb=ieee80211_association_req(pstat, ieee); ++ if (skb) ++ softmac_mgmt_xmit(skb, ieee); ++} ++ ++void ieee80211_ext_issue_disassoc(struct ieee80211_device *ieee, struct ieee80211_network *pstat, int reason, unsigned char extReason) ++{ ++ // do nothing ++ // printk("@@@@@ ieee80211_ext_issue_disassoc\n"); ++ return; ++} ++#endif // _RTL8187_EXT_PATCH_ ++ ++void ieee80211_associate_step2(struct ieee80211_device *ieee) ++{ ++ struct sk_buff* skb; ++ struct ieee80211_network *beacon = &ieee->current_network; ++ ++// del_timer_sync(&ieee->associate_timer); ++ ++ IEEE80211_DEBUG_MGMT("Sending association request\n"); ++ ++ ieee->softmac_stats.tx_ass_rq++; ++ skb=ieee80211_association_req(beacon, ieee); ++ if (!skb) ++ ieee80211_associate_abort(ieee); ++ else{ ++ softmac_mgmt_xmit(skb, ieee); ++ if(!timer_pending(&ieee->associate_timer)){ ++ ieee->associate_timer.expires = jiffies + (HZ / 2); ++ add_timer(&ieee->associate_timer); ++ } ++ dev_kfree_skb_any(skb);//edit by thomas ++ } ++} ++ ++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,20)) ++void ieee80211_associate_complete_wq(struct work_struct *work) ++{ ++ struct ieee80211_device *ieee = container_of(work, struct ieee80211_device, associate_complete_wq); ++#else ++void ieee80211_associate_complete_wq(struct ieee80211_device *ieee) ++{ ++#endif ++ printk(KERN_INFO "Associated successfully\n"); ++ if(ieee80211_is_54g(ieee->current_network) && ++ (ieee->modulation & IEEE80211_OFDM_MODULATION)){ ++ ++ ieee->rate = 540; ++ printk(KERN_INFO"Using G rates\n"); ++ }else{ ++ ieee->rate = 110; ++ printk(KERN_INFO"Using B rates\n"); ++ } ++ ++//by lizhaoming for LED LINK ++#ifdef LED_SHIN ++ { ++ struct net_device *dev = ieee->dev; ++ ieee->ieee80211_led_contorl(dev, LED_CTL_LINK); ++ } ++#endif ++ ++ ieee->link_change(ieee->dev); ++ notify_wx_assoc_event(ieee); ++ if (ieee->data_hard_resume) ++ ieee->data_hard_resume(ieee->dev); ++ netif_carrier_on(ieee->dev); ++} ++ ++void ieee80211_associate_complete(struct ieee80211_device *ieee) ++{ ++ int i; ++// struct net_device *dev = ieee->dev; ++ del_timer_sync(&ieee->associate_timer); ++ ++ for(i = 0; i < 6; i++) { ++// ieee->seq_ctrl[i] = 0; ++ } ++ ieee->state = IEEE80211_LINKED; ++ IEEE80211_DEBUG_MGMT("Successfully associated\n"); ++ ++ //by lizhaoming for LED LINK ++ //ieee->ieee80211_led_contorl(dev, LED_CTL_LINK); ++ ++#if LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0) ++ queue_work(ieee->wq, &ieee->associate_complete_wq); ++#else ++ schedule_task(&ieee->associate_complete_wq); ++#endif ++} ++ ++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,20)) ++void ieee80211_associate_procedure_wq(struct work_struct *work) ++{ ++ struct ieee80211_device *ieee = container_of(work, struct ieee80211_device, associate_procedure_wq); ++#else ++void ieee80211_associate_procedure_wq(struct ieee80211_device *ieee) ++{ ++#endif ++ ieee->sync_scan_hurryup = 1; ++ down(&ieee->wx_sem); ++ ++ if (ieee->data_hard_stop) ++ ieee->data_hard_stop(ieee->dev); ++ ++ ieee80211_stop_scan(ieee); ++ //printk("=======>%s set chan:%d\n", __func__, ieee->current_network.channel); ++ ieee->set_chan(ieee->dev, ieee->current_network.channel); ++ ++ ieee->associate_seq = 1; ++ ieee80211_associate_step1(ieee); ++ ++ up(&ieee->wx_sem); ++} ++#ifdef _RTL8187_EXT_PATCH_ ++// based on ieee80211_associate_procedure_wq ++ ++#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,20) ++void ieee80211_ext_stop_scan_wq(struct work_struct *work) ++{ ++ struct ieee80211_device *ieee = container_of(work, struct ieee80211_device, ext_stop_scan_wq); ++#else ++void ieee80211_ext_stop_scan_wq(struct ieee80211_device *ieee) ++{ ++#endif ++/* ++ if (ieee->scanning == 0) ++ { ++ if((ieee->iw_mode == ieee->iw_ext_mode) && ieee->ext_patch_ieee80211_ext_stop_scan_wq_set_channel ++ && ( ieee->current_network.channel == ieee->ext_patch_ieee80211_ext_stop_scan_wq_set_channel(ieee) ) ) ++ return; ++ } ++*/ ++ ieee->sync_scan_hurryup = 1; ++ ++ down(&ieee->wx_sem); ++ ++ // printk("@@@@@@@@@@ ieee80211_ext_stop_scan_wq\n"); ++ if (ieee->data_hard_stop) ++ ieee->data_hard_stop(ieee->dev); ++ ++ ieee80211_stop_scan(ieee); ++ ++ // set channel ++ if((ieee->iw_mode == ieee->iw_ext_mode) && ieee->ext_patch_ieee80211_ext_stop_scan_wq_set_channel) ++ { ++ int ch = ieee->ext_patch_ieee80211_ext_stop_scan_wq_set_channel(ieee); ++ ieee->current_network.channel = ch; ++ ieee->set_chan(ieee->dev, ch); ++ } ++ else ++ { ++ ieee->set_chan(ieee->dev, ieee->current_network.channel); ++ } ++ // ++ up(&ieee->wx_sem); ++} ++ ++ ++void ieee80211_ext_send_11s_beacon(struct ieee80211_device *ieee) ++{ ++ #if LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0) ++ queue_work(ieee->wq, &ieee->ext_send_beacon_wq); ++ #else ++ schedule_task(&ieee->ext_send_beacon_wq); ++ #endif ++ ++} ++ ++#endif // _RTL8187_EXT_PATCH_ ++ ++inline void ieee80211_softmac_new_net(struct ieee80211_device *ieee, struct ieee80211_network *net) ++{ ++ u8 tmp_ssid[IW_ESSID_MAX_SIZE+1]; ++ int tmp_ssid_len = 0; ++ ++ short apset,ssidset,ssidbroad,apmatch,ssidmatch; ++// printk("===============>%s()\n",__FUNCTION__); ++ /* we are interested in new new only if we are not associated ++ * and we are not associating / authenticating ++ */ ++ if (ieee->state != IEEE80211_NOLINK) ++ return; ++ ++ if ((ieee->iw_mode == IW_MODE_INFRA) && !(net->capability & WLAN_CAPABILITY_BSS)) ++ return; ++ ++ if ((ieee->iw_mode == IW_MODE_ADHOC) && !(net->capability & WLAN_CAPABILITY_IBSS)) ++ return; ++ ++ ++ if (ieee->iw_mode == IW_MODE_INFRA || ieee->iw_mode == IW_MODE_ADHOC){ ++ /* if the user specified the AP MAC, we need also the essid ++ * This could be obtained by beacons or, if the network does not ++ * broadcast it, it can be put manually. ++ */ ++ apset = ieee->wap_set;//(memcmp(ieee->current_network.bssid, zero,ETH_ALEN)!=0 ); ++ ssidset = ieee->ssid_set;//ieee->current_network.ssid[0] != '\0'; ++ ssidbroad = !(net->ssid_len == 0 || net->ssid[0]== '\0'); ++ apmatch = (memcmp(ieee->current_network.bssid, net->bssid, ETH_ALEN)==0); ++ if(ieee->current_network.ssid_len != net->ssid_len) ++ ssidmatch = 0; ++ else ++ ssidmatch = (0==strncmp(ieee->current_network.ssid, net->ssid, net->ssid_len)); ++ ++ ++ ++ if ( /* if the user set the AP check if match. ++ * if the network does not broadcast essid we check the user supplyed ANY essid ++ * if the network does broadcast and the user does not set essid it is OK ++ * if the network does broadcast and the user did set essid chech if essid match ++ */ ++ ( apset && apmatch && ++ //((ssidset && ssidbroad && ssidmatch) || (ssidbroad && !ssidset) || (!ssidbroad && ssidset)) ) || ++ ((ssidset && ssidbroad && ssidmatch) || (!ssidbroad && ssidset)) ) || ++ /* if the ap is not set, check that the user set the bssid ++ * and the network does bradcast and that those two bssid matches ++ */ ++ (!apset && ssidset && ssidbroad && ssidmatch) ++ ){ ++ /* if the essid is hidden replace it with the ++ * essid provided by the user. ++ */ ++ if (!ssidbroad){ ++ strncpy(tmp_ssid, ieee->current_network.ssid, IW_ESSID_MAX_SIZE); ++ tmp_ssid_len = ieee->current_network.ssid_len; ++ } ++ memcpy(&ieee->current_network, net, sizeof(struct ieee80211_network)); ++ ++ if (!ssidbroad){ ++ strncpy(ieee->current_network.ssid, tmp_ssid, IW_ESSID_MAX_SIZE); ++ ieee->current_network.ssid_len = tmp_ssid_len; ++ } ++ printk(KERN_INFO"Linking with %s, channel:%d\n",ieee->current_network.ssid, ieee->current_network.channel); ++ ++#ifdef CONFIG_IPS ++ ieee->ieee80211_ips_leave(ieee->dev); ++#endif ++ ++ if (ieee->iw_mode == IW_MODE_INFRA){ ++ ieee->state = IEEE80211_ASSOCIATING; ++#if LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0) ++ queue_work(ieee->wq, &ieee->associate_procedure_wq); ++#else ++ schedule_task(&ieee->associate_procedure_wq); ++#endif ++ }else{ ++ ieee->state = IEEE80211_LINKED; ++ if(ieee80211_is_54g(ieee->current_network) && ++ (ieee->modulation & IEEE80211_OFDM_MODULATION)){ ++ ieee->rate = 540; ++ printk(KERN_INFO"Using G rates\n"); ++ }else{ ++ ieee->rate = 110; ++ printk(KERN_INFO"Using B rates\n"); ++ } ++ } ++ ++ } ++ } ++ ++} ++ ++void ieee80211_softmac_check_all_nets(struct ieee80211_device *ieee) ++{ ++ unsigned long flags; ++ struct ieee80211_network *target; ++ ++ spin_lock_irqsave(&ieee->lock, flags); ++#if 0 ++ list_for_each_entry(target, &ieee->network_list, list) { ++ printk(KERN_INFO"check network list SSID: %s, channel: %d\n",target->ssid,target->channel); ++ } ++#endif ++ list_for_each_entry(target, &ieee->network_list, list) { ++ ++ /* if the state become different that NOLINK means ++ * we had found what we are searching for ++ */ ++ ++ if (ieee->state != IEEE80211_NOLINK) ++ break; ++ ++ if (ieee->scan_age == 0 || time_after(target->last_scanned + ieee->scan_age, jiffies)) ++ ieee80211_softmac_new_net(ieee, target); ++ } ++ ++ spin_unlock_irqrestore(&ieee->lock, flags); ++ ++ //printk("<=====%s\n", __func__); ++} ++ ++ ++static inline u16 auth_parse(struct sk_buff *skb, u8** challenge, int *chlen) ++{ ++ struct ieee80211_authentication *a; ++ u8 *t; ++ if (skb->len < (sizeof(struct ieee80211_authentication)-sizeof(struct ieee80211_info_element))){ ++ IEEE80211_DEBUG_MGMT("invalid len in auth resp: %d\n",skb->len); ++ return 0xcafe; ++ } ++ *challenge = NULL; ++ a = (struct ieee80211_authentication*) skb->data; ++ if(skb->len > (sizeof(struct ieee80211_authentication) +3)){ ++ t = skb->data + sizeof(struct ieee80211_authentication); ++ ++ if(*(t++) == MFIE_TYPE_CHALLENGE){ ++ *chlen = *(t++); ++ *challenge = (u8*)kmalloc(*chlen, GFP_ATOMIC); ++ memcpy(*challenge, t, *chlen); ++ } ++ } ++ ++ return cpu_to_le16(a->status); ++ ++} ++ ++ ++int auth_rq_parse(struct sk_buff *skb,u8* dest) ++{ ++ struct ieee80211_authentication *a; ++ ++ if (skb->len < (sizeof(struct ieee80211_authentication)-sizeof(struct ieee80211_info_element))){ ++ IEEE80211_DEBUG_MGMT("invalid len in auth request: %d\n",skb->len); ++ return -1; ++ } ++ a = (struct ieee80211_authentication*) skb->data; ++ ++ memcpy(dest,a->header.addr2, ETH_ALEN); ++ ++ if (le16_to_cpu(a->algorithm) != WLAN_AUTH_OPEN) ++ return WLAN_STATUS_NOT_SUPPORTED_AUTH_ALG; ++ ++ return WLAN_STATUS_SUCCESS; ++} ++ ++static short probe_rq_parse(struct ieee80211_device *ieee, struct sk_buff *skb, u8 *src) ++{ ++ u8 *tag; ++ u8 *skbend; ++ u8 *ssid=NULL; ++ u8 ssidlen = 0; ++ ++ struct ieee80211_hdr_3addr *header = ++ (struct ieee80211_hdr_3addr *) skb->data; ++ ++ if (skb->len < sizeof (struct ieee80211_hdr_3addr )) ++ return -1; /* corrupted */ ++ ++ memcpy(src,header->addr2, ETH_ALEN); ++ ++ skbend = (u8*)skb->data + skb->len; ++ ++ tag = skb->data + sizeof (struct ieee80211_hdr_3addr ); ++ ++ while (tag+1 < skbend){ ++ if (*tag == 0){ ++ ssid = tag+2; ++ ssidlen = *(tag+1); ++ break; ++ } ++ tag++; /* point to the len field */ ++ tag = tag + *(tag); /* point to the last data byte of the tag */ ++ tag++; /* point to the next tag */ ++ } ++ ++ //IEEE80211DMESG("Card MAC address is "MACSTR, MAC2STR(src)); ++ if (ssidlen == 0) return 1; ++ ++ if (!ssid) return 1; /* ssid not found in tagged param */ ++ return (!strncmp(ssid, ieee->current_network.ssid, ssidlen)); ++ ++} ++ ++int assoc_rq_parse(struct sk_buff *skb,u8* dest) ++{ ++ struct ieee80211_assoc_request_frame *a; ++ ++ if (skb->len < (sizeof(struct ieee80211_assoc_request_frame) - ++ sizeof(struct ieee80211_info_element))) { ++ ++ IEEE80211_DEBUG_MGMT("invalid len in auth request:%d \n", skb->len); ++ return -1; ++ } ++ ++ a = (struct ieee80211_assoc_request_frame*) skb->data; ++ ++ memcpy(dest,a->header.addr2,ETH_ALEN); ++ ++ return 0; ++} ++ ++static inline u16 assoc_parse(struct sk_buff *skb, int *aid) ++{ ++ struct ieee80211_assoc_response_frame *a; ++ if (skb->len < sizeof(struct ieee80211_assoc_response_frame)){ ++ IEEE80211_DEBUG_MGMT("invalid len in auth resp: %d\n", skb->len); ++ return 0xcafe; ++ } ++ ++ a = (struct ieee80211_assoc_response_frame*) skb->data; ++ *aid = le16_to_cpu(a->aid) & 0x3fff; ++ return le16_to_cpu(a->status); ++} ++ ++static inline void ++ieee80211_rx_probe_rq(struct ieee80211_device *ieee, struct sk_buff *skb) ++{ ++ u8 dest[ETH_ALEN]; ++ ++ //IEEE80211DMESG("Rx probe"); ++ ieee->softmac_stats.rx_probe_rq++; ++ //DMESG("Dest is "MACSTR, MAC2STR(dest)); ++ if (probe_rq_parse(ieee, skb, dest)){ ++ //IEEE80211DMESG("Was for me!"); ++ ieee->softmac_stats.tx_probe_rs++; ++ ieee80211_resp_to_probe(ieee, dest); ++ } ++} ++ ++//static inline void ++inline void ieee80211_rx_auth_rq(struct ieee80211_device *ieee, struct sk_buff *skb) ++{ ++ u8 dest[ETH_ALEN]; ++ int status; ++ //IEEE80211DMESG("Rx probe"); ++ ieee->softmac_stats.rx_auth_rq++; ++ ++ if ((status = auth_rq_parse(skb, dest))!= -1){ ++ ieee80211_resp_to_auth(ieee, status, dest); ++ } ++ //DMESG("Dest is "MACSTR, MAC2STR(dest)); ++ ++} ++ ++//static inline void ++inline void ++ieee80211_rx_assoc_rq(struct ieee80211_device *ieee, struct sk_buff *skb) ++{ ++ ++ u8 dest[ETH_ALEN]; ++ //unsigned long flags; ++ ++ ieee->softmac_stats.rx_ass_rq++; ++ if (assoc_rq_parse(skb,dest) != -1){ ++ ieee80211_resp_to_assoc_rq(ieee, dest); ++ } ++ ++ printk(KERN_INFO"New client associated: "MAC_FMT"\n", MAC_ARG(dest)); ++ //FIXME ++ #if 0 ++ spin_lock_irqsave(&ieee->lock,flags); ++ add_associate(ieee,dest); ++ spin_unlock_irqrestore(&ieee->lock,flags); ++ #endif ++} ++ ++ ++ ++void ieee80211_sta_ps_send_null_frame(struct ieee80211_device *ieee, short pwr) ++{ ++ ++ struct sk_buff *buf = ieee80211_null_func(ieee, pwr); ++ ++ printk(KERN_ALERT "ieee80211_sta_ps_send_null_frame \n"); ++ if (buf) ++ softmac_ps_mgmt_xmit(buf, ieee); ++ ++} ++ ++ ++short ieee80211_sta_ps_sleep(struct ieee80211_device *ieee, u32 *time_h, u32 *time_l) ++{ ++ int timeout = ieee->ps_timeout; ++ u8 dtim; ++ /*if(ieee->ps == IEEE80211_PS_DISABLED || ++ ieee->iw_mode != IW_MODE_INFRA || ++ ieee->state != IEEE80211_LINKED) ++ ++ return 0; ++ */ ++ dtim = ieee->current_network.dtim_data; ++ //printk("DTIM\n"); ++ if(!(dtim & IEEE80211_DTIM_VALID)) ++ return 0; ++ //printk("VALID\n"); ++ ieee->current_network.dtim_data = IEEE80211_DTIM_INVALID; ++ ++ if(dtim & ((IEEE80211_DTIM_UCAST | IEEE80211_DTIM_MBCAST)& ieee->ps)) ++ return 2; ++ ++ if(!time_after(jiffies, ieee->dev->trans_start + MSECS(timeout))) ++ return 0; ++ ++ if(!time_after(jiffies, ieee->last_rx_ps_time + MSECS(timeout))) ++ return 0; ++ ++ if((ieee->softmac_features & IEEE_SOFTMAC_SINGLE_QUEUE ) && ++ (ieee->mgmt_queue_tail != ieee->mgmt_queue_head)) ++ return 0; ++ ++ if(time_l){ ++ *time_l = ieee->current_network.last_dtim_sta_time[0] ++ + (ieee->current_network.beacon_interval ++ * ieee->current_network.dtim_period) * 1000; ++ } ++ ++ if(time_h){ ++ *time_h = ieee->current_network.last_dtim_sta_time[1]; ++ if(time_l && *time_l < ieee->current_network.last_dtim_sta_time[0]) ++ *time_h += 1; ++ } ++ ++ return 1; ++ ++ ++} ++ ++inline void ieee80211_sta_ps(struct ieee80211_device *ieee) ++{ ++ ++ u32 th,tl; ++ short sleep; ++ ++ unsigned long flags,flags2; ++ ++ spin_lock_irqsave(&ieee->lock, flags); ++ ++ if((ieee->ps == IEEE80211_PS_DISABLED || ++ ieee->iw_mode != IW_MODE_INFRA || ++ ieee->state != IEEE80211_LINKED)){ ++ ++ // #warning CHECK_LOCK_HERE ++ spin_lock_irqsave(&ieee->mgmt_tx_lock, flags2); ++ ++ ieee80211_sta_wakeup(ieee, 1); ++ ++ spin_unlock_irqrestore(&ieee->mgmt_tx_lock, flags2); ++ } ++ ++ sleep = ieee80211_sta_ps_sleep(ieee,&th, &tl); ++ /* 2 wake, 1 sleep, 0 do nothing */ ++ if(sleep == 0) ++ goto out; ++ ++ if(sleep == 1){ ++ ++ if(ieee->sta_sleep == 1) ++ ieee->enter_sleep_state(ieee->dev,th,tl); ++ ++ else if(ieee->sta_sleep == 0){ ++ // printk("send null 1\n"); ++ spin_lock_irqsave(&ieee->mgmt_tx_lock, flags2); ++ ++ if(ieee->ps_is_queue_empty(ieee->dev)){ ++ ++ ++ ieee->sta_sleep = 2; ++ ++ ieee->ps_request_tx_ack(ieee->dev); ++ ++ ieee80211_sta_ps_send_null_frame(ieee,1); ++ ++ ieee->ps_th = th; ++ ieee->ps_tl = tl; ++ } ++ spin_unlock_irqrestore(&ieee->mgmt_tx_lock, flags2); ++ ++ } ++ ++ ++ }else if(sleep == 2){ ++//#warning CHECK_LOCK_HERE ++ spin_lock_irqsave(&ieee->mgmt_tx_lock, flags2); ++ ++ ieee80211_sta_wakeup(ieee,1); ++ ++ spin_unlock_irqrestore(&ieee->mgmt_tx_lock, flags2); ++ } ++ ++out: ++ spin_unlock_irqrestore(&ieee->lock, flags); ++ ++} ++ ++void ieee80211_sta_wakeup(struct ieee80211_device *ieee, short nl) ++{ ++ if(ieee->sta_sleep == 0){ ++ if(nl){ ++ printk("Warning: driver is probably failing to report TX ps error\n"); ++ ieee->ps_request_tx_ack(ieee->dev); ++ ieee80211_sta_ps_send_null_frame(ieee, 0); ++ } ++ return; ++ ++ } ++ ++ if(ieee->sta_sleep == 1) ++ ieee->sta_wake_up(ieee->dev); ++ ++ ieee->sta_sleep = 0; ++ ++ if(nl){ ++ ieee->ps_request_tx_ack(ieee->dev); ++ ieee80211_sta_ps_send_null_frame(ieee, 0); ++ } ++} ++ ++void ieee80211_ps_tx_ack(struct ieee80211_device *ieee, short success) ++{ ++ unsigned long flags,flags2; ++ ++ spin_lock_irqsave(&ieee->lock, flags); ++ ++ if(ieee->sta_sleep == 2){ ++ /* Null frame with PS bit set */ ++ if(success){ ++ ieee->sta_sleep = 1; ++ ieee->enter_sleep_state(ieee->dev,ieee->ps_th,ieee->ps_tl); ++ } ++ /* if the card report not success we can't be sure the AP ++ * has not RXed so we can't assume the AP believe us awake ++ */ ++ } ++ /* 21112005 - tx again null without PS bit if lost */ ++ else { ++ ++ if((ieee->sta_sleep == 0) && !success){ ++ spin_lock_irqsave(&ieee->mgmt_tx_lock, flags2); ++ ieee80211_sta_ps_send_null_frame(ieee, 0); ++ spin_unlock_irqrestore(&ieee->mgmt_tx_lock, flags2); ++ } ++ } ++ spin_unlock_irqrestore(&ieee->lock, flags); ++} ++ ++inline int ++ieee80211_rx_frame_softmac(struct ieee80211_device *ieee, struct sk_buff *skb, ++ struct ieee80211_rx_stats *rx_stats, u16 type, ++ u16 stype) ++{ ++ struct ieee80211_hdr_3addr *header = (struct ieee80211_hdr_3addr *) skb->data; ++ u16 errcode; ++ u8* challenge=NULL; ++ int chlen=0; ++ int aid=0; ++ struct ieee80211_assoc_response_frame *assoc_resp; ++ struct ieee80211_info_element *info_element; ++ ++ if(!ieee->proto_started) ++ return 0; ++ ++ if(ieee->sta_sleep || (ieee->ps != IEEE80211_PS_DISABLED && ++ ieee->iw_mode == IW_MODE_INFRA && ++ ieee->state == IEEE80211_LINKED)) ++ ++ tasklet_schedule(&ieee->ps_task); ++ ++ if(WLAN_FC_GET_STYPE(header->frame_ctl) != IEEE80211_STYPE_PROBE_RESP && ++ WLAN_FC_GET_STYPE(header->frame_ctl) != IEEE80211_STYPE_BEACON) ++ ieee->last_rx_ps_time = jiffies; ++ ++ switch (WLAN_FC_GET_STYPE(header->frame_ctl)) { ++ case IEEE80211_STYPE_ASSOC_RESP: ++ case IEEE80211_STYPE_REASSOC_RESP: ++ ++ IEEE80211_DEBUG_MGMT("received [RE]ASSOCIATION RESPONSE (%d)\n", ++ WLAN_FC_GET_STYPE(header->frame_ctl)); ++ //printk(KERN_WARNING "Received association response\n"); ++ if ((ieee->softmac_features & IEEE_SOFTMAC_ASSOCIATE) && ++ ieee->state == IEEE80211_ASSOCIATING_AUTHENTICATED && ++ ieee->iw_mode == IW_MODE_INFRA){ ++ if (0 == (errcode=assoc_parse(skb, &aid))){ ++ u16 left; ++ ++ ieee->state=IEEE80211_LINKED; ++ ieee->assoc_id = aid; ++ ieee->softmac_stats.rx_ass_ok++; ++ ++ //printk(KERN_WARNING "nic_type = %s", (rx_stats->nic_type == 1)?"rtl8187":"rtl8187B"); ++ if(1 == rx_stats->nic_type) //card type is 8187 ++ { ++ goto associate_complete; ++ } ++ assoc_resp = (struct ieee80211_assoc_response_frame*)skb->data; ++ info_element = &assoc_resp->info_element; ++ left = skb->len - ((void*)info_element - (void*)assoc_resp); ++ ++ while (left >= sizeof(struct ieee80211_info_element_hdr)) { ++ if (sizeof(struct ieee80211_info_element_hdr) + info_element->len > left) { ++ printk(KERN_WARNING "[re]associate reeponse error!"); ++ return 1; ++ } ++ switch (info_element->id) { ++ case MFIE_TYPE_GENERIC: ++ IEEE80211_DEBUG_SCAN("MFIE_TYPE_GENERIC: %d bytes\n", info_element->len); ++ if (info_element->len >= 8 && ++ info_element->data[0] == 0x00 && ++ info_element->data[1] == 0x50 && ++ info_element->data[2] == 0xf2 && ++ info_element->data[3] == 0x02 && ++ info_element->data[4] == 0x01) { ++ // Not care about version at present. ++ //WMM Parameter Element ++ memcpy(ieee->current_network.wmm_param,(u8*)(info_element->data\ ++ + 8),(info_element->len - 8)); ++ ++ if (((ieee->current_network.wmm_info^info_element->data[6])& \ ++ 0x0f)||(!ieee->init_wmmparam_flag)) { ++ //refresh paramete element for current network ++ // update the register parameter for hardware ++ ieee->init_wmmparam_flag = 1; ++ //ieee->wmm_param_update(ieee); ++ //schedule_work(&ieee->wmm_param_update_wq); ++#if LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0) ++ queue_work(ieee->wq, &ieee->wmm_param_update_wq); ++#else ++ schedule_task(&ieee->wmm_param_update_wq); ++#endif ++ ++ } ++ //update info_element for current network ++ ieee->current_network.wmm_info = info_element->data[6]; ++ } ++ break; ++ default: ++ //nothing to do at present!!! ++ break; ++ } ++ ++ left -= sizeof(struct ieee80211_info_element_hdr) + ++ info_element->len; ++ info_element = (struct ieee80211_info_element *) ++ &info_element->data[info_element->len]; ++ } ++ if(!ieee->init_wmmparam_flag) //legacy AP, reset the AC_xx_param register ++ { ++#if LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0) ++ queue_work(ieee->wq,&ieee->wmm_param_update_wq); ++#else ++ schedule_task(&ieee->wmm_param_update_wq); ++#endif ++ ieee->init_wmmparam_flag = 1;//indicate AC_xx_param upated since last associate ++ } ++associate_complete: ++ ieee80211_associate_complete(ieee); ++ }else{ ++ ieee->softmac_stats.rx_ass_err++; ++ IEEE80211_DEBUG_MGMT( ++ "Association response status code 0x%x\n", ++ errcode); ++ printk(KERN_WARNING "Association response status code 0x%x\n", ++ errcode); ++ ieee80211_associate_abort(ieee); ++ } ++ } ++#ifdef _RTL8187_EXT_PATCH_ ++ else if ((ieee->iw_mode == ieee->iw_ext_mode) && ieee->ext_patch_ieee80211_rx_frame_softmac_on_assoc_rsp) ++ { ++ ieee->ext_patch_ieee80211_rx_frame_softmac_on_assoc_rsp(ieee, skb); ++ } ++#endif ++ break; ++ ++ case IEEE80211_STYPE_ASSOC_REQ: ++ case IEEE80211_STYPE_REASSOC_REQ: ++ //printk("Received IEEE80211_STYPE_ASSOC_REQ\n"); ++ ++ if ((ieee->softmac_features & IEEE_SOFTMAC_ASSOCIATE) && ++ ieee->iw_mode == IW_MODE_MASTER) ++ ++ ieee80211_rx_assoc_rq(ieee, skb); ++#ifdef _RTL8187_EXT_PATCH_ ++ else if ((ieee->iw_mode == ieee->iw_ext_mode) && ieee->ext_patch_ieee80211_rx_frame_softmac_on_assoc_req) ++ { ++ ieee->ext_patch_ieee80211_rx_frame_softmac_on_assoc_req(ieee, skb); ++ } ++#endif ++ break; ++ ++ case IEEE80211_STYPE_AUTH: ++ //printk("Received authentication response\n"); ++ ++#ifdef _RTL8187_EXT_PATCH_ ++//printk("IEEE80211_STYPE_AUTH\n"); ++ if((ieee->iw_mode == ieee->iw_ext_mode) && ieee->ext_patch_ieee80211_rx_frame_softmac_on_auth) ++ if( ieee->ext_patch_ieee80211_rx_frame_softmac_on_auth(ieee, skb, rx_stats) ); ++#endif ++ if (ieee->softmac_features & IEEE_SOFTMAC_ASSOCIATE){ ++ if (ieee->state == IEEE80211_ASSOCIATING_AUTHENTICATING && ++ ieee->iw_mode == IW_MODE_INFRA){ ++ ++ IEEE80211_DEBUG_MGMT("Received authentication response"); ++ ++ if (0 == (errcode=auth_parse(skb, &challenge, &chlen))){ ++ if(ieee->open_wep || !challenge){ ++ ieee->state = IEEE80211_ASSOCIATING_AUTHENTICATED; ++ ieee->softmac_stats.rx_auth_rs_ok++; ++ ++ ieee80211_associate_step2(ieee); ++ }else{ ++ ieee80211_auth_challenge(ieee, challenge, chlen); ++ } ++ }else{ ++ ieee->softmac_stats.rx_auth_rs_err++; ++ IEEE80211_DEBUG_MGMT("Authentication respose status code 0x%x",errcode); ++ ieee80211_associate_abort(ieee); ++ } ++ ++ }else if (ieee->iw_mode == IW_MODE_MASTER){ ++ ieee80211_rx_auth_rq(ieee, skb); ++ } ++ } ++ break; ++ ++ case IEEE80211_STYPE_PROBE_REQ: ++ //printk("Received IEEE80211_STYPE_PROBE_REQ\n"); ++ ++ if ((ieee->softmac_features & IEEE_SOFTMAC_PROBERS) && ++ ((ieee->iw_mode == IW_MODE_ADHOC || ++ ieee->iw_mode == IW_MODE_MASTER) && ++ ieee->state == IEEE80211_LINKED)) ++ ++ ieee80211_rx_probe_rq(ieee, skb); ++ break; ++ ++ case IEEE80211_STYPE_DISASSOC: ++ case IEEE80211_STYPE_DEAUTH: ++ //printk("Received IEEE80211_STYPE_DISASSOC\n"); ++#ifdef _RTL8187_EXT_PATCH_ ++//printk("IEEE80211_STYPE_DEAUTH\n"); ++ if((ieee->iw_mode == ieee->iw_ext_mode) && ieee->ext_patch_ieee80211_rx_frame_softmac_on_deauth) ++ if( ieee->ext_patch_ieee80211_rx_frame_softmac_on_deauth(ieee, skb, rx_stats) ) ; ++#endif ++ /* FIXME for now repeat all the association procedure ++ * both for disassociation and deauthentication ++ */ ++ if ((ieee->softmac_features & IEEE_SOFTMAC_ASSOCIATE) && ++ ieee->state == IEEE80211_LINKED && ++ ieee->iw_mode == IW_MODE_INFRA){ ++ ++ ieee->state = IEEE80211_ASSOCIATING; ++ ieee->softmac_stats.reassoc++; ++ ++ notify_wx_assoc_event(ieee); ++#if LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0) ++ queue_work(ieee->wq, &ieee->associate_procedure_wq); ++#else ++ schedule_task(&ieee->associate_procedure_wq); ++#endif ++ } ++ ++ break; ++ ++ default: ++ return -1; ++ break; ++ } ++ ++ //dev_kfree_skb_any(skb); ++ return 0; ++} ++ ++ ++ ++/* following are for a simplier TX queue management. ++ * Instead of using netif_[stop/wake]_queue the driver ++ * will uses these two function (plus a reset one), that ++ * will internally uses the kernel netif_* and takes ++ * care of the ieee802.11 fragmentation. ++ * So the driver receives a fragment per time and might ++ * call the stop function when it want without take care ++ * to have enought room to TX an entire packet. ++ * This might be useful if each fragment need it's own ++ * descriptor, thus just keep a total free memory > than ++ * the max fragmentation treshold is not enought.. If the ++ * ieee802.11 stack passed a TXB struct then you needed ++ * to keep N free descriptors where ++ * N = MAX_PACKET_SIZE / MIN_FRAG_TRESHOLD ++ * In this way you need just one and the 802.11 stack ++ * will take care of buffering fragments and pass them to ++ * to the driver later, when it wakes the queue. ++ */ ++ ++void ieee80211_softmac_xmit(struct ieee80211_txb *txb, struct ieee80211_device *ieee) ++{ ++ ++ ++ unsigned long flags; ++ int i; ++#ifdef _RTL8187_EXT_PATCH_ ++ int rate = ieee->rate; ++#endif ++ ++ spin_lock_irqsave(&ieee->lock,flags); ++ #if 0 ++ if(ieee->queue_stop){ ++ IEEE80211DMESG("EE: IEEE hard_start_xmit invoked when kernel queue should be stopped"); ++ netif_stop_queue(ieee->dev); ++ ieee->ieee_stats.swtxstop++; ++ //dev_kfree_skb_any(skb); ++ err = 1; ++ goto exit; ++ } ++ ++ ieee->stats.tx_bytes+=skb->len; ++ ++ ++ txb=ieee80211_skb_to_txb(ieee,skb); ++ ++ ++ if(txb==NULL){ ++ IEEE80211DMESG("WW: IEEE stack failed to provide txb"); ++ //dev_kfree_skb_any(skb); ++ err = 1; ++ goto exit; ++ } ++ #endif ++ ++#ifdef _RTL8187_EXT_PATCH_ ++ if((ieee->iw_mode == ieee->iw_ext_mode) && ieee->ext_patch_ieee80211_softmac_xmit_get_rate && txb->nr_frags) ++ { ++ rate = ieee->ext_patch_ieee80211_softmac_xmit_get_rate(ieee, txb->fragments[0]); ++ } ++#endif ++ /* called with 2nd parm 0, no tx mgmt lock required */ ++ ieee80211_sta_wakeup(ieee,0); ++ ++ for(i = 0; i < txb->nr_frags; i++) { ++ ++ if (ieee->queue_stop){ ++ ieee->tx_pending.txb = txb; ++ ieee->tx_pending.frag = i; ++ goto exit; ++ }else{ ++ ieee->softmac_data_hard_start_xmit( ++ txb->fragments[i], ++#ifdef _RTL8187_EXT_PATCH_ ++ ieee->dev, rate); ++#else ++ ieee->dev,ieee->rate); ++#endif ++ //(i+1)<txb->nr_frags); ++ ieee->stats.tx_packets++; ++ ieee->stats.tx_bytes += txb->fragments[i]->len; ++ ieee->dev->trans_start = jiffies; ++ } ++ } ++ ++ ieee80211_txb_free(txb); ++ ++ exit: ++ spin_unlock_irqrestore(&ieee->lock,flags); ++ ++} ++ ++/* called with ieee->lock acquired */ ++void ieee80211_resume_tx(struct ieee80211_device *ieee) ++{ ++ int i; ++ for(i = ieee->tx_pending.frag; i < ieee->tx_pending.txb->nr_frags; i++) { ++ ++ if (ieee->queue_stop){ ++ ieee->tx_pending.frag = i; ++ return; ++ }else{ ++ ++ ieee->softmac_data_hard_start_xmit( ++ ieee->tx_pending.txb->fragments[i], ++ ieee->dev,ieee->rate); ++ //(i+1)<ieee->tx_pending.txb->nr_frags); ++ ieee->stats.tx_packets++; ++ ieee->dev->trans_start = jiffies; ++ } ++ } ++ ++ ++ ieee80211_txb_free(ieee->tx_pending.txb); ++ ieee->tx_pending.txb = NULL; ++} ++ ++ ++void ieee80211_reset_queue(struct ieee80211_device *ieee) ++{ ++ unsigned long flags; ++ ++ spin_lock_irqsave(&ieee->lock,flags); ++ init_mgmt_queue(ieee); ++ if (ieee->tx_pending.txb){ ++ ieee80211_txb_free(ieee->tx_pending.txb); ++ ieee->tx_pending.txb = NULL; ++ } ++ ieee->queue_stop = 0; ++ spin_unlock_irqrestore(&ieee->lock,flags); ++ ++} ++ ++void ieee80211_wake_queue(struct ieee80211_device *ieee) ++{ ++ ++ unsigned long flags; ++ struct sk_buff *skb; ++ struct ieee80211_hdr_3addr *header; ++ ++ spin_lock_irqsave(&ieee->lock,flags); ++ if (! ieee->queue_stop) goto exit; ++ ++ ieee->queue_stop = 0; ++ ++ if(ieee->softmac_features & IEEE_SOFTMAC_SINGLE_QUEUE){ ++ while (!ieee->queue_stop && (skb = dequeue_mgmt(ieee))){ ++ ++ header = (struct ieee80211_hdr_3addr *) skb->data; ++ ++ header->seq_ctl = cpu_to_le16(ieee->seq_ctrl[0] << 4); ++ ++ if (ieee->seq_ctrl[0] == 0xFFF) ++ ieee->seq_ctrl[0] = 0; ++ else ++ ieee->seq_ctrl[0]++; ++ ++ printk(KERN_ALERT "ieee80211_wake_queue \n"); ++ ieee->softmac_data_hard_start_xmit(skb,ieee->dev,ieee->basic_rate); ++ dev_kfree_skb_any(skb);//edit by thomas ++ } ++ } ++ if (!ieee->queue_stop && ieee->tx_pending.txb) ++ ieee80211_resume_tx(ieee); ++ ++ if (!ieee->queue_stop && netif_queue_stopped(ieee->dev)){ ++ ieee->softmac_stats.swtxawake++; ++ netif_wake_queue(ieee->dev); ++ } ++ ++exit : ++ spin_unlock_irqrestore(&ieee->lock,flags); ++} ++ ++ ++void ieee80211_stop_queue(struct ieee80211_device *ieee) ++{ ++ //unsigned long flags; ++ //spin_lock_irqsave(&ieee->lock,flags); ++ ++ if (! netif_queue_stopped(ieee->dev)){ ++ netif_stop_queue(ieee->dev); ++ ieee->softmac_stats.swtxstop++; ++ } ++ ieee->queue_stop = 1; ++ //spin_unlock_irqrestore(&ieee->lock,flags); ++ ++} ++ ++ ++inline void ieee80211_randomize_cell(struct ieee80211_device *ieee) ++{ ++ ++ get_random_bytes(ieee->current_network.bssid, ETH_ALEN); ++ ++ /* an IBSS cell address must have the two less significant ++ * bits of the first byte = 2 ++ */ ++ ieee->current_network.bssid[0] &= ~0x01; ++ ieee->current_network.bssid[0] |= 0x02; ++} ++ ++/* called in user context only */ ++void ieee80211_start_master_bss(struct ieee80211_device *ieee) ++{ ++ ieee->assoc_id = 1; ++ ++ if (ieee->current_network.ssid_len == 0){ ++ strncpy(ieee->current_network.ssid, ++ IEEE80211_DEFAULT_TX_ESSID, ++ IW_ESSID_MAX_SIZE); ++ ++ ieee->current_network.ssid_len = strlen(IEEE80211_DEFAULT_TX_ESSID); ++ ieee->ssid_set = 1; ++ } ++ ++ memcpy(ieee->current_network.bssid, ieee->dev->dev_addr, ETH_ALEN); ++ ++ ieee->set_chan(ieee->dev, ieee->current_network.channel); ++ ieee->state = IEEE80211_LINKED; ++ ++//by lizhaoming for LED LINK ++#ifdef LED_SHIN ++ { ++ struct net_device *dev = ieee->dev; ++ ieee->ieee80211_led_contorl(dev, LED_CTL_LINK); ++ } ++#endif ++ ieee->link_change(ieee->dev); ++ notify_wx_assoc_event(ieee); ++ ++ if (ieee->data_hard_resume) ++ ieee->data_hard_resume(ieee->dev); ++ ++ netif_carrier_on(ieee->dev); ++} ++ ++void ieee80211_start_monitor_mode(struct ieee80211_device *ieee) ++{ ++ if(ieee->raw_tx){ ++ ++ if (ieee->data_hard_resume) ++ ieee->data_hard_resume(ieee->dev); ++ ++ netif_carrier_on(ieee->dev); ++ } ++} ++ ++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,20)) ++void ieee80211_start_ibss_wq(struct work_struct *work) ++{ ++ struct delayed_work *dwork = container_of(work, struct delayed_work, work); ++ struct ieee80211_device *ieee = container_of(dwork, struct ieee80211_device, start_ibss_wq); ++#else ++void ieee80211_start_ibss_wq(struct ieee80211_device *ieee) ++{ ++#endif ++ ++ /* iwconfig mode ad-hoc will schedule this and return ++ * on the other hand this will block further iwconfig SET ++ * operations because of the wx_sem hold. ++ * Anyway some most set operations set a flag to speed-up ++ * (abort) this wq (when syncro scanning) before sleeping ++ * on the semaphore ++ */ ++ ++ down(&ieee->wx_sem); ++ ++ if (ieee->current_network.ssid_len == 0){ ++ strcpy(ieee->current_network.ssid,IEEE80211_DEFAULT_TX_ESSID); ++ ieee->current_network.ssid_len = strlen(IEEE80211_DEFAULT_TX_ESSID); ++ ieee->ssid_set = 1; ++ } ++ ++//by lizhaoming for LED BLINK 2008.6.23 ++#ifdef LED_SHIN ++ { ++ struct net_device *dev = ieee->dev; ++ ieee->ieee80211_led_contorl(dev, LED_CTL_SITE_SURVEY); ++ } ++#endif ++ ++ /* check if we have this cell in our network list */ ++ ieee80211_softmac_check_all_nets(ieee); ++ ++#ifdef ENABLE_DOT11D ++ //[World wide 13]: ++ // Adhoc: ++ // (1) active scan from ch1~11 and passive scan from ch12~13 ++ // (2) IBSS can join ch1~13 adhoc, but only start at ch10. ++ if(ieee->state == IEEE80211_NOLINK) ++ if(ieee->IbssStartChnl != 0) ++ ieee->current_network.channel = ieee->IbssStartChnl;//chan 10 ++#endif ++ ++ /* if not then the state is not linked. Maybe the user swithced to ++ * ad-hoc mode just after being in monitor mode, or just after ++ * being very few time in managed mode (so the card have had no ++ * time to scan all the chans..) or we have just run up the iface ++ * after setting ad-hoc mode. So we have to give another try.. ++ * Here, in ibss mode, should be safe to do this without extra care ++ * (in bss mode we had to make sure no-one tryed to associate when ++ * we had just checked the ieee->state and we was going to start the ++ * scan) beacause in ibss mode the ieee80211_new_net function, when ++ * finds a good net, just set the ieee->state to IEEE80211_LINKED, ++ * so, at worst, we waste a bit of time to initiate an unneeded syncro ++ * scan, that will stop at the first round because it sees the state ++ * associated. ++ */ ++ if (ieee->state == IEEE80211_NOLINK){ ++ ieee80211_start_scan_syncro(ieee); ++ } ++ ++ /* the network definitively is not here.. create a new cell */ ++ if (ieee->state == IEEE80211_NOLINK){ ++ printk("creating new IBSS cell\n"); ++ ieee->state = IEEE80211_LINKED; ++ if(!ieee->wap_set) ++ ieee80211_randomize_cell(ieee); ++ ++ if(ieee->modulation & IEEE80211_CCK_MODULATION){ ++ ++ ieee->current_network.rates_len = 4; ++ ++ ieee->current_network.rates[0] = IEEE80211_BASIC_RATE_MASK | IEEE80211_CCK_RATE_1MB; ++ ieee->current_network.rates[1] = IEEE80211_BASIC_RATE_MASK | IEEE80211_CCK_RATE_2MB; ++ ieee->current_network.rates[2] = IEEE80211_BASIC_RATE_MASK | IEEE80211_CCK_RATE_5MB; ++ ieee->current_network.rates[3] = IEEE80211_BASIC_RATE_MASK | IEEE80211_CCK_RATE_11MB; ++ ++ }else ++ ieee->current_network.rates_len = 0; ++ ++ if(ieee->modulation & IEEE80211_OFDM_MODULATION){ ++ ieee->current_network.rates_ex_len = 8; ++ ++ ieee->current_network.rates_ex[0] = IEEE80211_BASIC_RATE_MASK | IEEE80211_OFDM_RATE_6MB; ++ ieee->current_network.rates_ex[1] = IEEE80211_BASIC_RATE_MASK | IEEE80211_OFDM_RATE_9MB; ++ ieee->current_network.rates_ex[2] = IEEE80211_BASIC_RATE_MASK | IEEE80211_OFDM_RATE_12MB; ++ ieee->current_network.rates_ex[3] = IEEE80211_BASIC_RATE_MASK | IEEE80211_OFDM_RATE_18MB; ++ ieee->current_network.rates_ex[4] = IEEE80211_BASIC_RATE_MASK | IEEE80211_OFDM_RATE_24MB; ++ ieee->current_network.rates_ex[5] = IEEE80211_BASIC_RATE_MASK | IEEE80211_OFDM_RATE_36MB; ++ ieee->current_network.rates_ex[6] = IEEE80211_BASIC_RATE_MASK | IEEE80211_OFDM_RATE_48MB; ++ ieee->current_network.rates_ex[7] = IEEE80211_BASIC_RATE_MASK | IEEE80211_OFDM_RATE_54MB; ++ ++ ieee->rate = 540; ++ }else{ ++ ieee->current_network.rates_ex_len = 0; ++ ieee->rate = 110; ++ } ++ ++ // By default, WMM function will be disabled in IBSS mode ++ ieee->current_network.QoS_Enable = 0; ++ ++ ieee->current_network.atim_window = 0; ++ ieee->current_network.capability = WLAN_CAPABILITY_IBSS; ++ if(ieee->short_slot) ++ ieee->current_network.capability |= WLAN_CAPABILITY_SHORT_SLOT; ++ ++ } ++ ++ ieee->state = IEEE80211_LINKED; ++ ++//by lizhaoming for LED LINK ++#ifdef LED_SHIN ++ { ++ struct net_device *dev = ieee->dev; ++ ieee->ieee80211_led_contorl(dev, LED_CTL_LINK); ++ } ++#endif ++ ++ ieee->set_chan(ieee->dev, ieee->current_network.channel); ++ ieee->link_change(ieee->dev); ++ ++ notify_wx_assoc_event(ieee); ++ ++ ieee80211_start_send_beacons(ieee); ++ printk(KERN_WARNING "after sending beacon packet!\n"); ++ ++ if (ieee->data_hard_resume) ++ ieee->data_hard_resume(ieee->dev); ++ ++ netif_carrier_on(ieee->dev); ++ ++ up(&ieee->wx_sem); ++} ++ ++inline void ieee80211_start_ibss(struct ieee80211_device *ieee) ++{ ++#if LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0) ++ queue_delayed_work(ieee->wq, &ieee->start_ibss_wq, 150); //change to delayed work, delayed time is need to check ++#else ++ schedule_task(&ieee->start_ibss_wq); ++#endif ++} ++ ++/* this is called only in user context, with wx_sem held */ ++void ieee80211_start_bss(struct ieee80211_device *ieee) ++{ ++ unsigned long flags; ++ /* check if we have already found the net we ++ * are interested in (if any). ++ * if not (we are disassociated and we are not ++ * in associating / authenticating phase) start the background scanning. ++ */ ++ ++//by lizhaoming for LED BLINK 2008.6.23 ++#ifdef LED_SHIN ++ { ++ struct net_device *dev = ieee->dev; ++ ieee->ieee80211_led_contorl(dev, LED_CTL_SITE_SURVEY); ++ } ++#endif ++ ++#ifdef ENABLE_DOT11D ++ // ++ // Ref: 802.11d 11.1.3.3 ++ // STA shall not start a BSS unless properly formed Beacon frame including a Country IE. ++ // ++ if(IS_DOT11D_ENABLE(ieee) && !IS_COUNTRY_IE_VALID(ieee)) ++ { ++ if(! ieee->bGlobalDomain) ++ { ++ return; ++ } ++ } ++#endif ++ //printk("======>%s()\n",__FUNCTION__); ++ ieee80211_softmac_check_all_nets(ieee); ++ ++ /* ensure no-one start an associating process (thus setting ++ * the ieee->state to ieee80211_ASSOCIATING) while we ++ * have just cheked it and we are going to enable scan. ++ * The ieee80211_new_net function is always called with ++ * lock held (from both ieee80211_softmac_check_all_nets and ++ * the rx path), so we cannot be in the middle of such function ++ */ ++ ++ spin_lock_irqsave(&ieee->lock, flags); ++ if (ieee->state == IEEE80211_NOLINK){ ++ //printk("Not find SSID in network list scan now\n"); ++ ieee80211_start_scan(ieee); ++ } ++ spin_unlock_irqrestore(&ieee->lock, flags); ++ ++} ++ ++/* called only in userspace context */ ++void ieee80211_disassociate(struct ieee80211_device *ieee) ++{ ++ netif_carrier_off(ieee->dev); ++ ++ if (ieee->softmac_features & IEEE_SOFTMAC_TX_QUEUE) ++ ieee80211_reset_queue(ieee); ++ ++ if (ieee->data_hard_stop) ++ ieee->data_hard_stop(ieee->dev); ++ ++#ifdef ENABLE_DOT11D ++ if(IS_DOT11D_ENABLE(ieee)) ++ Dot11d_Reset(ieee); ++#endif ++ ++ ieee->state = IEEE80211_NOLINK; ++ ieee->link_change(ieee->dev); ++ notify_wx_assoc_event(ieee); ++ ++} ++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,20)) ++void ieee80211_associate_retry_wq(struct work_struct *work) ++{ ++ struct delayed_work *dwork = container_of(work, struct delayed_work, work); ++ struct ieee80211_device *ieee = container_of(dwork, struct ieee80211_device, associate_retry_wq); ++#else ++void ieee80211_associate_retry_wq(struct ieee80211_device *ieee) ++{ ++#endif ++ unsigned long flags; ++ ++ down(&ieee->wx_sem); ++ if(!ieee->proto_started) ++ goto exit; ++ ++ if(ieee->state != IEEE80211_ASSOCIATING_RETRY) ++ goto exit; ++ ++ /* until we do not set the state to IEEE80211_NOLINK ++ * there are no possibility to have someone else trying ++ * to start an association procdure (we get here with ++ * ieee->state = IEEE80211_ASSOCIATING). ++ * When we set the state to IEEE80211_NOLINK it is possible ++ * that the RX path run an attempt to associate, but ++ * both ieee80211_softmac_check_all_nets and the ++ * RX path works with ieee->lock held so there are no ++ * problems. If we are still disassociated then start a scan. ++ * the lock here is necessary to ensure no one try to start ++ * an association procedure when we have just checked the ++ * state and we are going to start the scan. ++ */ ++ ieee->state = IEEE80211_NOLINK; ++ ++ ieee80211_softmac_check_all_nets(ieee); ++ ++ spin_lock_irqsave(&ieee->lock, flags); ++ if(ieee->state == IEEE80211_NOLINK) ++ { ++ printk("%s():Not find SSID:%s[ch=%d, mode=%s] in network list scan now\n", __FUNCTION__, ++ ieee->current_network.ssid,ieee->current_network.channel, ++ (ieee->iw_mode == IW_MODE_INFRA) ? "BSS" : "IBSS"); ++ ++ ieee80211_start_scan(ieee); ++ } ++ ++ spin_unlock_irqrestore(&ieee->lock, flags); ++ ++exit: ++ up(&ieee->wx_sem); ++} ++ ++struct sk_buff *ieee80211_get_beacon_(struct ieee80211_device *ieee) ++{ ++ u8 broadcast_addr[] = {0xff,0xff,0xff,0xff,0xff,0xff}; ++ ++ struct sk_buff *skb = NULL; ++ struct ieee80211_probe_response *b; ++ ++//rz ++#ifdef _RTL8187_EXT_PATCH_ ++ if((ieee->iw_mode == ieee->iw_ext_mode) && ieee->ext_patch_get_beacon_get_probersp ) ++ skb = ieee->ext_patch_get_beacon_get_probersp(ieee, broadcast_addr, &(ieee->current_network)); ++ else ++ skb = ieee80211_probe_resp(ieee, broadcast_addr); ++#else ++ skb = ieee80211_probe_resp(ieee, broadcast_addr); ++#endif ++// ++ if (!skb) ++ return NULL; ++ ++ b = (struct ieee80211_probe_response *) skb->data; ++ b->header.frame_ctl = cpu_to_le16(IEEE80211_STYPE_BEACON); ++ ++ return skb; ++ ++} ++ ++struct sk_buff *ieee80211_get_beacon(struct ieee80211_device *ieee) ++{ ++ struct sk_buff *skb; ++ struct ieee80211_probe_response *b; ++// printk("=========>%s()\n", __FUNCTION__); ++ skb = ieee80211_get_beacon_(ieee); ++ if(!skb) ++ return NULL; ++ ++ b = (struct ieee80211_probe_response *) skb->data; ++ b->header.seq_ctrl = cpu_to_le16(ieee->seq_ctrl[0] << 4); ++ ++ if (ieee->seq_ctrl[0] == 0xFFF) ++ ieee->seq_ctrl[0] = 0; ++ else ++ ieee->seq_ctrl[0]++; ++ ++ return skb; ++} ++ ++void ieee80211_softmac_stop_protocol(struct ieee80211_device *ieee) ++{ ++ ieee->sync_scan_hurryup = 1; ++ down(&ieee->wx_sem); ++ ieee80211_stop_protocol(ieee); ++ up(&ieee->wx_sem); ++} ++ ++ ++void ieee80211_stop_protocol(struct ieee80211_device *ieee) ++{ ++ if (!ieee->proto_started) ++ return; ++ ++ ieee->proto_started = 0; ++ //printk("=====>%s\n", __func__); ++ ++#ifdef _RTL8187_EXT_PATCH_ ++ if(ieee->ext_patch_ieee80211_stop_protocol) ++ ieee->ext_patch_ieee80211_stop_protocol(ieee); ++//if call queue_delayed_work,can call this,or do nothing.. ++//edit by lawrence,20071118 ++#if LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0) ++// cancel_delayed_work(&ieee->ext_stop_scan_wq); ++// cancel_delayed_work(&ieee->ext_send_beacon_wq); ++#endif ++#endif // _RTL8187_EXT_PATCH_ ++ ++ ieee80211_stop_send_beacons(ieee); ++ ++ del_timer_sync(&ieee->associate_timer); ++#if LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0) ++ cancel_delayed_work(&ieee->associate_retry_wq); ++ cancel_delayed_work(&ieee->start_ibss_wq); //cancel ibss start workqueue when stop protocol ++#endif ++ ieee80211_stop_scan(ieee); ++ ++ ieee80211_disassociate(ieee); ++ //printk("<=====%s\n", __func__); ++ ++} ++ ++void ieee80211_softmac_start_protocol(struct ieee80211_device *ieee) ++{ ++ ieee->sync_scan_hurryup = 0; ++ down(&ieee->wx_sem); ++ ieee80211_start_protocol(ieee); ++ up(&ieee->wx_sem); ++} ++ ++void ieee80211_start_protocol(struct ieee80211_device *ieee) ++{ ++ short ch = 0; ++ int i = 0; ++ ++ if (ieee->proto_started) ++ return; ++ ++ //printk("=====>%s\n", __func__); ++ ++ ieee->proto_started = 1; ++ ++ if (ieee->current_network.channel == 0){ ++ do{ ++ ch++; ++ if (ch > MAX_CHANNEL_NUMBER) ++ return; /* no channel found */ ++#ifdef ENABLE_DOT11D ++ }while(!GET_DOT11D_INFO(ieee)->channel_map[ch]); ++#else ++ }while(!ieee->channel_map[ch]); ++#endif ++ ieee->current_network.channel = ch; ++ } ++ ++ if (ieee->current_network.beacon_interval == 0) ++ ieee->current_network.beacon_interval = 100; ++ ++ ieee->set_chan(ieee->dev,ieee->current_network.channel); ++ mdelay(10);//must or link change will fail lzm ++ ++ for(i = 0; i < 17; i++) { ++ ieee->last_rxseq_num[i] = -1; ++ ieee->last_rxfrag_num[i] = -1; ++ ieee->last_packet_time[i] = 0; ++ } ++ ++ ieee->init_wmmparam_flag = 0;//reinitialize AC_xx_PARAM registers. ++ ++ ++ /* if the user set the MAC of the ad-hoc cell and then ++ * switch to managed mode, shall we make sure that association ++ * attempts does not fail just because the user provide the essid ++ * and the nic is still checking for the AP MAC ?? ++ */ ++ ++ if (ieee->iw_mode == IW_MODE_INFRA){ ++ ieee80211_start_bss(ieee); ++ // printk("==========> IW_MODE_INFRA\n"); ++ } ++ else if (ieee->iw_mode == IW_MODE_ADHOC){ ++ // printk("==========> IW_MODE_ADHOC\n"); ++ ieee80211_start_ibss(ieee); ++ } ++ else if (ieee->iw_mode == IW_MODE_MASTER){ ++ ieee80211_start_master_bss(ieee); ++// printk("==========> IW_MODE_MASTER\n"); ++ } ++ else if(ieee->iw_mode == IW_MODE_MONITOR){ ++ ieee80211_start_monitor_mode(ieee); ++// printk("==========> IW_MODE_MONITOR\n"); ++ } ++ ++#ifdef _RTL8187_EXT_PATCH_ ++// else if((ieee->iw_mode == ieee->iw_ext_mode) && ieee->ext_patch_ieee80211_start_protocol && ieee->ext_patch_ieee80211_start_protocol(ieee)) ++ else if((ieee->iw_mode == ieee->iw_ext_mode) && ieee->ext_patch_ieee80211_start_protocol) ++ { ++ ieee->ext_patch_ieee80211_start_mesh(ieee); ++ } ++#endif ++} ++ ++ ++#define DRV_NAME "Ieee80211" ++void ieee80211_softmac_init(struct ieee80211_device *ieee) ++{ ++ int i; ++ memset(&ieee->current_network, 0, sizeof(struct ieee80211_network)); ++ ++ ieee->state = IEEE80211_NOLINK; ++ ieee->sync_scan_hurryup = 0; ++ for(i = 0; i < 5; i++) { ++ ieee->seq_ctrl[i] = 0; ++ } ++ ++ ieee->assoc_id = 0; ++ ieee->queue_stop = 0; ++ ieee->scanning = 0; ++ ieee->scan_watchdog = 0;//lzm add 081215 for roaming ++ ieee->softmac_features = 0; //so IEEE2100-like driver are happy ++ ieee->wap_set = 0; ++ ieee->ssid_set = 0; ++ ieee->proto_started = 0; ++ ieee->basic_rate = IEEE80211_DEFAULT_BASIC_RATE; ++ ieee->rate = 3; ++ ieee->ps = IEEE80211_PS_DISABLED; ++ ieee->sta_sleep = 0; ++//by amy ++ ieee->bInactivePs = false; ++ ieee->actscanning = false; ++ ieee->ListenInterval = 2; ++ ieee->NumRxData = 0; ++ ieee->NumRxDataInPeriod = 0; //YJ,add,080828 ++ ieee->NumRxBcnInPeriod = 0; //YJ,add,080828 ++ ieee->bHwRadioOff = false;//by lizhaoming ++//by amy ++#ifdef _RTL8187_EXT_PATCH_ ++ ieee->iw_ext_mode = 999; ++#endif ++ ++ init_mgmt_queue(ieee); ++ ++#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0) ++ init_timer(&ieee->scan_timer); ++ ieee->scan_timer.data = (unsigned long)ieee; ++ ieee->scan_timer.function = ieee80211_softmac_scan_cb; ++#endif ++ ieee->tx_pending.txb = NULL; ++ ++ init_timer(&ieee->associate_timer); ++ ieee->associate_timer.data = (unsigned long)ieee; ++ ieee->associate_timer.function = ieee80211_associate_abort_cb; ++ ++ init_timer(&ieee->beacon_timer); ++ ieee->beacon_timer.data = (unsigned long) ieee; ++ ieee->beacon_timer.function = ieee80211_send_beacon_cb; ++ ++#if LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0) ++#ifdef PF_SYNCTHREAD ++ ieee->wq = create_workqueue(DRV_NAME,0); ++#else ++ ieee->wq = create_workqueue(DRV_NAME); ++#endif ++#endif ++#if LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0) ++#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,20)//added by lawrence,070702 ++ INIT_DELAYED_WORK(&ieee->start_ibss_wq, ieee80211_start_ibss_wq); ++ INIT_WORK(&ieee->associate_complete_wq, ieee80211_associate_complete_wq); ++ INIT_WORK(&ieee->associate_procedure_wq, ieee80211_associate_procedure_wq); ++ INIT_DELAYED_WORK(&ieee->softmac_scan_wq, ieee80211_softmac_scan_wq); ++ INIT_DELAYED_WORK(&ieee->associate_retry_wq, ieee80211_associate_retry_wq); ++ INIT_WORK(&ieee->wx_sync_scan_wq, ieee80211_wx_sync_scan_wq); ++//added by lawrence,20071118 ++#ifdef _RTL8187_EXT_PATCH_ ++ INIT_WORK(&ieee->ext_stop_scan_wq, ieee80211_ext_stop_scan_wq); ++ //INIT_WORK(&ieee->ext_send_beacon_wq, ieee80211_beacons_start,ieee); ++ INIT_WORK(&ieee->ext_send_beacon_wq, ext_ieee80211_send_beacon_wq); ++#endif //_RTL8187_EXT_PATCH_ ++#else ++ INIT_WORK(&ieee->start_ibss_wq,(void(*)(void*)) ieee80211_start_ibss_wq,ieee); ++ INIT_WORK(&ieee->associate_retry_wq,(void(*)(void*)) ieee80211_associate_retry_wq,ieee); ++ INIT_WORK(&ieee->associate_complete_wq,(void(*)(void*)) ieee80211_associate_complete_wq,ieee); ++ INIT_WORK(&ieee->associate_procedure_wq,(void(*)(void*)) ieee80211_associate_procedure_wq,ieee); ++ INIT_WORK(&ieee->softmac_scan_wq,(void(*)(void*)) ieee80211_softmac_scan_wq,ieee); ++ INIT_WORK(&ieee->wx_sync_scan_wq,(void(*)(void*)) ieee80211_wx_sync_scan_wq,ieee); ++#ifdef _RTL8187_EXT_PATCH_ ++ INIT_WORK(&ieee->ext_stop_scan_wq,(void(*)(void*)) ieee80211_ext_stop_scan_wq,ieee); ++ //INIT_WORK(&ieee->ext_send_beacon_wq,(void(*)(void*)) ieee80211_beacons_start,ieee); ++ INIT_WORK(&ieee->ext_send_beacon_wq,(void(*)(void*)) ext_ieee80211_send_beacon_wq,ieee); ++#endif ++#endif ++#else ++ tq_init(&ieee->start_ibss_wq,(void(*)(void*)) ieee80211_start_ibss_wq,ieee); ++ tq_init(&ieee->associate_retry_wq,(void(*)(void*)) ieee80211_associate_retry_wq,ieee); ++ tq_init(&ieee->associate_complete_wq,(void(*)(void*)) ieee80211_associate_complete_wq,ieee); ++ tq_init(&ieee->associate_procedure_wq,(void(*)(void*)) ieee80211_associate_procedure_wq,ieee); ++ tq_init(&ieee->softmac_scan_wq,(void(*)(void*)) ieee80211_softmac_scan_wq,ieee); ++ tq_init(&ieee->wx_sync_scan_wq,(void(*)(void*)) ieee80211_wx_sync_scan_wq,ieee); ++#ifdef _RTL8187_EXT_PATCH_ ++ tq_init(&ieee->ext_stop_scan_wq,(void(*)(void*)) ieee80211_ext_stop_scan_wq,ieee); ++ //tq_init(&ieee->ext_send_beacon_wq,(void(*)(void*)) ieee80211_beacons_start,ieee); ++ tq_init(&ieee->ext_send_beacon_wq,(void(*)(void*)) ext_ieee80211_send_beacon_wq,ieee); ++#endif ++#endif ++ sema_init(&ieee->wx_sem, 1); ++ sema_init(&ieee->scan_sem, 1); ++ sema_init(&ieee->ips_sem,1); ++ spin_lock_init(&ieee->mgmt_tx_lock); ++ spin_lock_init(&ieee->beacon_lock); ++ spin_lock_init(&ieee->beaconflag_lock); ++ tasklet_init(&ieee->ps_task, ++ (void(*)(unsigned long)) ieee80211_sta_ps, ++ (unsigned long)ieee); ++#ifdef ENABLE_DOT11D ++ ieee->pDot11dInfo = kmalloc(sizeof(RT_DOT11D_INFO), GFP_ATOMIC); ++#endif ++ ++} ++ ++void ieee80211_softmac_free(struct ieee80211_device *ieee) ++{ ++ down(&ieee->wx_sem); ++ ++ del_timer_sync(&ieee->associate_timer); ++ ++#if LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0) ++ cancel_delayed_work(&ieee->associate_retry_wq); ++ ++ ++ ++#ifdef _RTL8187_EXT_PATCH_ ++ //When kernel>2.6.20,crash.... ++// cancel_delayed_work(&ieee->ext_stop_scan_wq); ++// cancel_delayed_work(&ieee->ext_send_beacon_wq); ++#endif ++ destroy_workqueue(ieee->wq); ++#endif ++ ++#ifdef ENABLE_DOT11D ++ if(NULL != ieee->pDot11dInfo) ++ kfree(ieee->pDot11dInfo); ++#endif ++ ++ up(&ieee->wx_sem); ++} ++ ++/******************************************************** ++ * Start of WPA code. * ++ * this is stolen from the ipw2200 driver * ++ ********************************************************/ ++ ++ ++static int ieee80211_wpa_enable(struct ieee80211_device *ieee, int value) ++{ ++ /* This is called when wpa_supplicant loads and closes the driver ++ * interface. */ ++ printk("%s WPA\n",value ? "enabling" : "disabling"); ++ ieee->wpa_enabled = value; ++ return 0; ++} ++ ++ ++void ieee80211_wpa_assoc_frame(struct ieee80211_device *ieee, char *wpa_ie, int wpa_ie_len) ++{ ++ /* make sure WPA is enabled */ ++ ieee80211_wpa_enable(ieee, 1); ++ ++ ieee80211_disassociate(ieee); ++} ++ ++ ++static int ieee80211_wpa_mlme(struct ieee80211_device *ieee, int command, int reason) ++{ ++ ++ int ret = 0; ++ ++ switch (command) { ++ case IEEE_MLME_STA_DEAUTH: ++ // silently ignore ++ break; ++ ++ case IEEE_MLME_STA_DISASSOC: ++ ieee80211_disassociate(ieee); ++ break; ++ ++ default: ++ printk("Unknown MLME request: %d\n", command); ++ ret = -EOPNOTSUPP; ++ } ++ ++ return ret; ++} ++ ++ ++static int ieee80211_wpa_set_wpa_ie(struct ieee80211_device *ieee, ++ struct ieee_param *param, int plen) ++{ ++ u8 *buf; ++ ++ if (param->u.wpa_ie.len > MAX_WPA_IE_LEN || ++ (param->u.wpa_ie.len && param->u.wpa_ie.data == NULL)) ++ return -EINVAL; ++ ++ if (param->u.wpa_ie.len) { ++ buf = kmalloc(param->u.wpa_ie.len, GFP_KERNEL); ++ if (buf == NULL) ++ return -ENOMEM; ++ ++ memcpy(buf, param->u.wpa_ie.data, param->u.wpa_ie.len); ++ kfree(ieee->wpa_ie); ++ ieee->wpa_ie = buf; ++ ieee->wpa_ie_len = param->u.wpa_ie.len; ++ } else { ++ kfree(ieee->wpa_ie); ++ ieee->wpa_ie = NULL; ++ ieee->wpa_ie_len = 0; ++ } ++ ++ ieee80211_wpa_assoc_frame(ieee, ieee->wpa_ie, ieee->wpa_ie_len); ++ return 0; ++} ++ ++#define AUTH_ALG_OPEN_SYSTEM 0x1 ++#define AUTH_ALG_SHARED_KEY 0x2 ++ ++static int ieee80211_wpa_set_auth_algs(struct ieee80211_device *ieee, int value) ++{ ++ ++ struct ieee80211_security sec = { ++ .flags = SEC_AUTH_MODE, ++ }; ++ int ret = 0; ++ ++ if (value & AUTH_ALG_SHARED_KEY) { ++ sec.auth_mode = WLAN_AUTH_SHARED_KEY; ++ ieee->open_wep = 0; ++ } else { ++ sec.auth_mode = WLAN_AUTH_OPEN; ++ ieee->open_wep = 1; ++ } ++ ++ if (ieee->set_security) ++ ieee->set_security(ieee->dev, &sec); ++ else ++ ret = -EOPNOTSUPP; ++ ++ return ret; ++} ++ ++static int ieee80211_wpa_set_param(struct ieee80211_device *ieee, u8 name, u32 value) ++{ ++ int ret=0; ++ unsigned long flags; ++ ++ switch (name) { ++ case IEEE_PARAM_WPA_ENABLED: ++ ret = ieee80211_wpa_enable(ieee, value); ++ break; ++ ++ case IEEE_PARAM_TKIP_COUNTERMEASURES: ++ ieee->tkip_countermeasures=value; ++ break; ++ ++ case IEEE_PARAM_DROP_UNENCRYPTED: { ++ /* HACK: ++ * ++ * wpa_supplicant calls set_wpa_enabled when the driver ++ * is loaded and unloaded, regardless of if WPA is being ++ * used. No other calls are made which can be used to ++ * determine if encryption will be used or not prior to ++ * association being expected. If encryption is not being ++ * used, drop_unencrypted is set to false, else true -- we ++ * can use this to determine if the CAP_PRIVACY_ON bit should ++ * be set. ++ */ ++ struct ieee80211_security sec = { ++ .flags = SEC_ENABLED, ++ .enabled = value, ++ }; ++ ieee->drop_unencrypted = value; ++ /* We only change SEC_LEVEL for open mode. Others ++ * are set by ipw_wpa_set_encryption. ++ */ ++ if (!value) { ++ sec.flags |= SEC_LEVEL; ++ sec.level = SEC_LEVEL_0; ++ } ++ else { ++ sec.flags |= SEC_LEVEL; ++ sec.level = SEC_LEVEL_1; ++ } ++ if (ieee->set_security) ++ ieee->set_security(ieee->dev, &sec); ++ break; ++ } ++ ++ case IEEE_PARAM_PRIVACY_INVOKED: ++ ieee->privacy_invoked=value; ++ break; ++ ++ case IEEE_PARAM_AUTH_ALGS: ++ ret = ieee80211_wpa_set_auth_algs(ieee, value); ++ break; ++ ++ case IEEE_PARAM_IEEE_802_1X: ++ ieee->ieee802_1x=value; ++ break; ++ case IEEE_PARAM_WPAX_SELECT: ++ // added for WPA2 mixed mode ++ //printk(KERN_WARNING "------------------------>wpax value = %x\n", value); ++ spin_lock_irqsave(&ieee->wpax_suitlist_lock,flags); ++ ieee->wpax_type_set = 1; ++ ieee->wpax_type_notify = value; ++ spin_unlock_irqrestore(&ieee->wpax_suitlist_lock,flags); ++ break; ++ ++ default: ++ printk("Unknown WPA param: %d\n",name); ++ ret = -EOPNOTSUPP; ++ } ++ ++ return ret; ++} ++ ++/* implementation borrowed from hostap driver */ ++ ++static int ieee80211_wpa_set_encryption(struct ieee80211_device *ieee, ++ struct ieee_param *param, int param_len) ++{ ++ int ret = 0; ++ ++ struct ieee80211_crypto_ops *ops; ++ struct ieee80211_crypt_data **crypt; ++ ++ struct ieee80211_security sec = { ++ .flags = 0, ++ }; ++ ++ param->u.crypt.err = 0; ++ param->u.crypt.alg[IEEE_CRYPT_ALG_NAME_LEN - 1] = '\0'; ++ ++ if (param_len != ++ (int) ((char *) param->u.crypt.key - (char *) param) + ++ param->u.crypt.key_len) { ++ printk("Len mismatch %d, %d\n", param_len, ++ param->u.crypt.key_len); ++ return -EINVAL; ++ } ++ if (param->sta_addr[0] == 0xff && param->sta_addr[1] == 0xff && ++ param->sta_addr[2] == 0xff && param->sta_addr[3] == 0xff && ++ param->sta_addr[4] == 0xff && param->sta_addr[5] == 0xff) { ++ if (param->u.crypt.idx >= WEP_KEYS) ++ return -EINVAL; ++#ifdef _RTL8187_EXT_PATCH_ ++ crypt = &ieee->cryptlist[0]->crypt[param->u.crypt.idx]; ++#else ++ crypt = &ieee->crypt[param->u.crypt.idx]; ++#endif ++ ++ } else { ++ return -EINVAL; ++ } ++ ++ if (strcmp(param->u.crypt.alg, "none") == 0) { ++ if (crypt) { ++ sec.enabled = 0; ++ // FIXME FIXME ++ //sec.encrypt = 0; ++ sec.level = SEC_LEVEL_0; ++ sec.flags |= SEC_ENABLED | SEC_LEVEL; ++ ieee80211_crypt_delayed_deinit(ieee, crypt); ++ } ++ goto done; ++ } ++ sec.enabled = 1; ++// FIXME FIXME ++// sec.encrypt = 1; ++ sec.flags |= SEC_ENABLED; ++ ++ /* IPW HW cannot build TKIP MIC, host decryption still needed. */ ++ if (!(ieee->host_encrypt || ieee->host_decrypt) && ++ strcmp(param->u.crypt.alg, "TKIP")) ++ goto skip_host_crypt; ++ ++ ops = ieee80211_get_crypto_ops(param->u.crypt.alg); ++ if (ops == NULL && strcmp(param->u.crypt.alg, "WEP") == 0) { ++ request_module("ieee80211_crypt_wep"); ++ ops = ieee80211_get_crypto_ops(param->u.crypt.alg); ++ } else if (ops == NULL && strcmp(param->u.crypt.alg, "TKIP") == 0) { ++ request_module("ieee80211_crypt_tkip"); ++ ops = ieee80211_get_crypto_ops(param->u.crypt.alg); ++ } else if (ops == NULL && strcmp(param->u.crypt.alg, "CCMP") == 0) { ++ request_module("ieee80211_crypt_ccmp"); ++ ops = ieee80211_get_crypto_ops(param->u.crypt.alg); ++ } ++ if (ops == NULL) { ++ printk("unknown crypto alg '%s'\n", param->u.crypt.alg); ++ param->u.crypt.err = IEEE_CRYPT_ERR_UNKNOWN_ALG; ++ ret = -EINVAL; ++ goto done; ++ } ++ ++#ifdef _RTL8187_EXT_PATCH_ ++ u8 i; ++ for (i=0; i<MAX_MP; i++){ ++ crypt = &ieee->cryptlist[i]->crypt[param->u.crypt.idx]; ++// if (crypt != NULL) printk("crypt not null\n", crypt); ++ ++ *crypt = ieee->cryptlist[i]->crypt[param->u.crypt.idx]; ++#endif ++ if (*crypt == NULL || (*crypt)->ops != ops) { ++ struct ieee80211_crypt_data *new_crypt; ++ ++ ieee80211_crypt_delayed_deinit(ieee, crypt); ++ ++ new_crypt = (struct ieee80211_crypt_data *) ++ kmalloc(sizeof(*new_crypt), GFP_KERNEL); ++ if (new_crypt == NULL) { ++ ret = -ENOMEM; ++ goto done; ++ } ++ memset(new_crypt, 0, sizeof(struct ieee80211_crypt_data)); ++ new_crypt->ops = ops; ++#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0) ++ if (new_crypt->ops && try_module_get(new_crypt->ops->owner)) ++#else ++ if (new_crypt->ops && try_inc_mod_count(new_crypt->ops->owner)) ++#endif ++ new_crypt->priv = ++ new_crypt->ops->init(param->u.crypt.idx); ++ ++ if (new_crypt->priv == NULL) { ++ kfree(new_crypt); ++ param->u.crypt.err = IEEE_CRYPT_ERR_CRYPT_INIT_FAILED; ++ ret = -EINVAL; ++ goto done; ++ } ++ ++ *crypt = new_crypt; ++ } ++ ++ if (param->u.crypt.key_len > 0 && (*crypt)->ops->set_key && ++ (*crypt)->ops->set_key(param->u.crypt.key, ++ param->u.crypt.key_len, param->u.crypt.seq, ++ (*crypt)->priv) < 0) { ++ printk("key setting failed\n"); ++ param->u.crypt.err = IEEE_CRYPT_ERR_KEY_SET_FAILED; ++ ret = -EINVAL; ++ goto done; ++ } ++#ifdef _RTL8187_EXT_PATCH_ ++ } ++#endif ++ skip_host_crypt: ++ if (param->u.crypt.set_tx) { ++ ieee->tx_keyidx = param->u.crypt.idx; ++ sec.active_key = param->u.crypt.idx; ++ sec.flags |= SEC_ACTIVE_KEY; ++ } else ++ sec.flags &= ~SEC_ACTIVE_KEY; ++ ++ if (param->u.crypt.alg != NULL) { ++ memcpy(sec.keys[param->u.crypt.idx], ++ param->u.crypt.key, ++ param->u.crypt.key_len); ++ sec.key_sizes[param->u.crypt.idx] = param->u.crypt.key_len; ++ sec.flags |= (1 << param->u.crypt.idx); ++ ++ if (strcmp(param->u.crypt.alg, "WEP") == 0) { ++ sec.flags |= SEC_LEVEL; ++ sec.level = SEC_LEVEL_1; ++ } else if (strcmp(param->u.crypt.alg, "TKIP") == 0) { ++ sec.flags |= SEC_LEVEL; ++ sec.level = SEC_LEVEL_2; ++ } else if (strcmp(param->u.crypt.alg, "CCMP") == 0) { ++ sec.flags |= SEC_LEVEL; ++ sec.level = SEC_LEVEL_3; ++ } ++ } ++ done: ++ if (ieee->set_security) ++ ieee->set_security(ieee->dev, &sec); ++#if 1 ++#ifdef _RTL8187_EXT_PATCH_ ++ if (ret != 0)//error out ++ { ++ for (i=0; i<MAX_MP; i++) ++ { ++ if (ieee->cryptlist[i]->crypt[param->u.crypt.idx]==NULL){ ++ break; ++ } ++ else{ ++ //if (ieee->cryptlist[i]->crypt[param->u.crypt.idx] != NULL) ++ // { ++ kfree(ieee->cryptlist[i]->crypt[param->u.crypt.idx]); ++ ieee->cryptlist[i]->crypt[param->u.crypt.idx] = NULL; ++ // } ++ // kfree(ieee->cryptlist[i]); ++ // ieee->cryptlist[i] = NULL; ++ } ++ } ++ } ++#endif ++#endif ++ /* Do not reset port if card is in Managed mode since resetting will ++ * generate new IEEE 802.11 authentication which may end up in looping ++ * with IEEE 802.1X. If your hardware requires a reset after WEP ++ * configuration (for example... Prism2), implement the reset_port in ++ * the callbacks structures used to initialize the 802.11 stack. */ ++ if (ieee->reset_on_keychange && ++ ieee->iw_mode != IW_MODE_INFRA && ++ ieee->reset_port && ++ ieee->reset_port(ieee->dev)) { ++ printk("reset_port failed\n"); ++ param->u.crypt.err = IEEE_CRYPT_ERR_CARD_CONF_FAILED; ++ return -EINVAL; ++ } ++ ++ return ret; ++} ++ ++int ieee80211_wpa_supplicant_ioctl(struct ieee80211_device *ieee, struct iw_point *p) ++{ ++ struct ieee_param *param; ++ int ret=0; ++ ++ down(&ieee->wx_sem); ++ //IEEE_DEBUG_INFO("wpa_supplicant: len=%d\n", p->length); ++ ++ if (p->length < sizeof(struct ieee_param) || !p->pointer){ ++ ret = -EINVAL; ++ goto out; ++ } ++ ++ param = (struct ieee_param *)kmalloc(p->length, GFP_KERNEL); ++ if (param == NULL){ ++ ret = -ENOMEM; ++ goto out; ++ } ++ if (copy_from_user(param, p->pointer, p->length)) { ++ kfree(param); ++ ret = -EFAULT; ++ goto out; ++ } ++ ++ switch (param->cmd) { ++ ++ case IEEE_CMD_SET_WPA_PARAM: ++ ret = ieee80211_wpa_set_param(ieee, param->u.wpa_param.name, ++ param->u.wpa_param.value); ++ break; ++ ++ case IEEE_CMD_SET_WPA_IE: ++ ret = ieee80211_wpa_set_wpa_ie(ieee, param, p->length); ++ break; ++ ++ case IEEE_CMD_SET_ENCRYPTION: ++ ret = ieee80211_wpa_set_encryption(ieee, param, p->length); ++ break; ++ ++ case IEEE_CMD_MLME: ++ ret = ieee80211_wpa_mlme(ieee, param->u.mlme.command, ++ param->u.mlme.reason_code); ++ break; ++ ++ default: ++ printk("Unknown WPA supplicant request: %d\n",param->cmd); ++ ret = -EOPNOTSUPP; ++ break; ++ } ++ ++ if (ret == 0 && copy_to_user(p->pointer, param, p->length)) ++ ret = -EFAULT; ++ ++ kfree(param); ++out: ++ up(&ieee->wx_sem); ++ ++ return ret; ++} ++ ++void notify_wx_assoc_event(struct ieee80211_device *ieee) ++{ ++ union iwreq_data wrqu; ++ wrqu.ap_addr.sa_family = ARPHRD_ETHER; ++ if (ieee->state == IEEE80211_LINKED) ++ memcpy(wrqu.ap_addr.sa_data, ieee->current_network.bssid, ETH_ALEN); ++ else ++ memset(wrqu.ap_addr.sa_data, 0, ETH_ALEN); ++ wireless_send_event(ieee->dev, SIOCGIWAP, &wrqu, NULL); ++} ++ ++#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0)) ++EXPORT_SYMBOL(ieee80211_get_beacon); ++EXPORT_SYMBOL(ieee80211_wake_queue); ++EXPORT_SYMBOL(ieee80211_stop_queue); ++EXPORT_SYMBOL(ieee80211_reset_queue); ++EXPORT_SYMBOL(ieee80211_softmac_stop_protocol); ++EXPORT_SYMBOL(ieee80211_softmac_start_protocol); ++EXPORT_SYMBOL(ieee80211_is_shortslot); ++EXPORT_SYMBOL(ieee80211_is_54g); ++EXPORT_SYMBOL(ieee80211_wpa_supplicant_ioctl); ++EXPORT_SYMBOL(ieee80211_ps_tx_ack); ++EXPORT_SYMBOL(notify_wx_assoc_event); ++EXPORT_SYMBOL(ieee80211_stop_send_beacons); ++EXPORT_SYMBOL(ieee80211_start_send_beacons); ++EXPORT_SYMBOL(ieee80211_start_scan_syncro); ++EXPORT_SYMBOL(ieee80211_start_protocol); ++EXPORT_SYMBOL(ieee80211_stop_protocol); ++EXPORT_SYMBOL(ieee80211_start_scan); ++EXPORT_SYMBOL(ieee80211_stop_scan); ++#ifdef _RTL8187_EXT_PATCH_ ++EXPORT_SYMBOL(ieee80211_ext_issue_assoc_req); ++EXPORT_SYMBOL(ieee80211_ext_issue_disassoc); ++EXPORT_SYMBOL(ieee80211_ext_issue_assoc_rsp); ++EXPORT_SYMBOL(softmac_mgmt_xmit); ++EXPORT_SYMBOL(ieee80211_ext_probe_resp_by_net); ++EXPORT_SYMBOL(ieee80211_stop_scan); ++EXPORT_SYMBOL(ieee80211_ext_send_11s_beacon); ++EXPORT_SYMBOL(ieee80211_rx_auth_rq); ++EXPORT_SYMBOL(ieee80211_associate_step1); ++#endif // _RTL8187_EXT_PATCH_ ++#else ++EXPORT_SYMBOL_NOVERS(ieee80211_get_beacon); ++EXPORT_SYMBOL_NOVERS(ieee80211_wake_queue); ++EXPORT_SYMBOL_NOVERS(ieee80211_stop_queue); ++EXPORT_SYMBOL_NOVERS(ieee80211_reset_queue); ++EXPORT_SYMBOL_NOVERS(ieee80211_softmac_stop_protocol); ++EXPORT_SYMBOL_NOVERS(ieee80211_softmac_start_protocol); ++EXPORT_SYMBOL_NOVERS(ieee80211_is_shortslot); ++EXPORT_SYMBOL_NOVERS(ieee80211_is_54g); ++EXPORT_SYMBOL_NOVERS(ieee80211_wpa_supplicant_ioctl); ++EXPORT_SYMBOL_NOVERS(ieee80211_ps_tx_ack); ++EXPORT_SYMBOL_NOVERS(ieee80211_start_scan); ++EXPORT_SYMBOL_NOVERS(ieee80211_stop_scan); ++#ifdef _RTL8187_EXT_PATCH_ ++EXPORT_SYMBOL_NOVERS(ieee80211_ext_issue_assoc_req); ++EXPORT_SYMBOL_NOVERS(ieee80211_ext_issue_disassoc); ++EXPORT_SYMBOL_NOVERS(ieee80211_ext_issue_assoc_rsp); ++EXPORT_SYMBOL_NOVERS(softmac_mgmt_xmit); ++EXPORT_SYMBOL_NOVERS(ieee80211_ext_probe_resp_by_net); ++EXPORT_SYMBOL_NOVERS(ieee80211_stop_scan); ++EXPORT_SYMBOL_NOVERS(ieee80211_ext_send_11s_beacon); ++EXPORT_SYMBOL_NOVERS(ieee80211_rx_auth_rq); ++EXPORT_SYMBOL(ieee80211_associate_step1); ++#endif // _RTL8187_EXT_PATCH_ ++ ++#endif ++//EXPORT_SYMBOL(ieee80211_sta_ps_send_null_frame); +diff -Nur linux-2.6.33/drivers/net/wireless/rtl8187b/ieee80211/ieee80211_softmac_wx.c linux-lemote/drivers/net/wireless/rtl8187b/ieee80211/ieee80211_softmac_wx.c +--- linux-2.6.33/drivers/net/wireless/rtl8187b/ieee80211/ieee80211_softmac_wx.c 1970-01-01 01:00:00.000000000 +0100 ++++ linux-lemote/drivers/net/wireless/rtl8187b/ieee80211/ieee80211_softmac_wx.c 2010-03-06 16:43:22.000000000 +0100 +@@ -0,0 +1,629 @@ ++/* IEEE 802.11 SoftMAC layer ++ * Copyright (c) 2005 Andrea Merello <andreamrl@tiscali.it> ++ * ++ * Mostly extracted from the rtl8180-sa2400 driver for the ++ * in-kernel generic ieee802.11 stack. ++ * ++ * Some pieces of code might be stolen from ipw2100 driver ++ * copyright of who own it's copyright ;-) ++ * ++ * PS wx handler mostly stolen from hostap, copyright who ++ * own it's copyright ;-) ++ * ++ * released under the GPL ++ */ ++ ++ ++#include "ieee80211.h" ++#ifdef ENABLE_DOT11D ++#include "dot11d.h" ++#endif ++ ++/* FIXME: add A freqs */ ++ ++const long ieee80211_wlan_frequencies[] = { ++ 2412, 2417, 2422, 2427, ++ 2432, 2437, 2442, 2447, ++ 2452, 2457, 2462, 2467, ++ 2472, 2484 ++}; ++ ++ ++int ieee80211_wx_set_freq(struct ieee80211_device *ieee, struct iw_request_info *a, ++ union iwreq_data *wrqu, char *b) ++{ ++ int ret; ++ struct iw_freq *fwrq = & wrqu->freq; ++ ++ down(&ieee->wx_sem); ++ ++ if(ieee->iw_mode == IW_MODE_INFRA){ ++ ret = -EOPNOTSUPP; ++ goto out; ++ } ++ ++ /* if setting by freq convert to channel */ ++ if (fwrq->e == 1) { ++ if ((fwrq->m >= (int) 2.412e8 && ++ fwrq->m <= (int) 2.487e8)) { ++ int f = fwrq->m / 100000; ++ int c = 0; ++ ++ while ((c < 14) && (f != ieee80211_wlan_frequencies[c])) ++ c++; ++ ++ /* hack to fall through */ ++ fwrq->e = 0; ++ fwrq->m = c + 1; ++ } ++ } ++ ++ if (fwrq->e > 0 || fwrq->m > 14 || fwrq->m < 1 ){ ++ ret = -EOPNOTSUPP; ++ goto out; ++ ++ }else { /* Set the channel */ ++ ++#ifdef ENABLE_DOT11D ++ if(!IsLegalChannel(ieee, fwrq->m) ) ++ { ++ printk("channel(%d). is invalide\n", fwrq->m); ++ ret = -EOPNOTSUPP; ++ goto out; ++ } ++ else ++ { ++ if(ieee->iw_mode == IW_MODE_ADHOC) ++ { ++ if(ieee->MinPassiveChnlNum != MAX_CHANNEL_NUMBER+1) ++ { ++ if(fwrq->m >= ieee->MinPassiveChnlNum) ++ { ++ ret = -EOPNOTSUPP; ++ goto out; ++ } ++ } ++ } ++ } ++#endif ++ ieee->current_network.channel = fwrq->m; ++ ieee->set_chan(ieee->dev, ieee->current_network.channel); ++ ++ if(ieee->iw_mode == IW_MODE_ADHOC || ieee->iw_mode == IW_MODE_MASTER) ++ if(ieee->state == IEEE80211_LINKED){ ++ ++ ieee80211_stop_send_beacons(ieee); ++ ieee80211_start_send_beacons(ieee); ++ } ++ } ++ ++ ret = 0; ++out: ++ up(&ieee->wx_sem); ++ return ret; ++} ++ ++ ++int ieee80211_wx_get_freq(struct ieee80211_device *ieee, ++ struct iw_request_info *a, ++ union iwreq_data *wrqu, char *b) ++{ ++ struct iw_freq *fwrq = & wrqu->freq; ++ ++ if (ieee->current_network.channel == 0) ++ return -1; ++ ++ fwrq->m = ieee->current_network.channel; ++ fwrq->e = 0; ++ ++ return 0; ++} ++ ++int ieee80211_wx_get_wap(struct ieee80211_device *ieee, ++ struct iw_request_info *info, ++ union iwreq_data *wrqu, char *extra) ++{ ++ unsigned long flags; ++ ++ wrqu->ap_addr.sa_family = ARPHRD_ETHER; ++ ++ if (ieee->iw_mode == IW_MODE_MONITOR) ++ return -1; ++ ++ /* We want avoid to give to the user inconsistent infos*/ ++ spin_lock_irqsave(&ieee->lock, flags); ++ ++ if (ieee->state != IEEE80211_LINKED && ++ ieee->state != IEEE80211_LINKED_SCANNING && ++ ieee->wap_set == 0) ++ ++ memset(wrqu->ap_addr.sa_data, 0, ETH_ALEN); ++ else ++ memcpy(wrqu->ap_addr.sa_data, ++ ieee->current_network.bssid, ETH_ALEN); ++ ++ spin_unlock_irqrestore(&ieee->lock, flags); ++ ++ return 0; ++} ++ ++ ++int ieee80211_wx_set_wap(struct ieee80211_device *ieee, ++ struct iw_request_info *info, ++ union iwreq_data *awrq, ++ char *extra) ++{ ++ ++ int ret = 0; ++ u8 zero[] = {0,0,0,0,0,0}; ++ unsigned long flags; ++ ++ short ifup = ieee->proto_started;//dev->flags & IFF_UP; ++ struct sockaddr *temp = (struct sockaddr *)awrq; ++ ++ ieee->sync_scan_hurryup = 1; ++ ++ down(&ieee->wx_sem); ++ /* use ifconfig hw ether */ ++ if (ieee->iw_mode == IW_MODE_MASTER){ ++ ret = -1; ++ goto out; ++ } ++ ++ if (temp->sa_family != ARPHRD_ETHER){ ++ ret = -EINVAL; ++ goto out; ++ } ++ ++ if (ifup) ++ ieee80211_stop_protocol(ieee); ++ ++ /* just to avoid to give inconsistent infos in the ++ * get wx method. not really needed otherwise ++ */ ++ spin_lock_irqsave(&ieee->lock, flags); ++ ++ memcpy(ieee->current_network.bssid, temp->sa_data, ETH_ALEN); ++ ieee->wap_set = memcmp(temp->sa_data, zero,ETH_ALEN)!=0; ++ ++ spin_unlock_irqrestore(&ieee->lock, flags); ++ ++ if (ifup) ++ ieee80211_start_protocol(ieee); ++ ++out: ++ up(&ieee->wx_sem); ++ return ret; ++} ++ ++ int ieee80211_wx_get_essid(struct ieee80211_device *ieee, struct iw_request_info *a,union iwreq_data *wrqu,char *b) ++{ ++ int len,ret = 0; ++ unsigned long flags; ++ ++ if (ieee->iw_mode == IW_MODE_MONITOR) ++ return -1; ++ ++ /* We want avoid to give to the user inconsistent infos*/ ++ spin_lock_irqsave(&ieee->lock, flags); ++ ++ if (ieee->current_network.ssid[0] == '\0' || ++ ieee->current_network.ssid_len == 0){ ++ ret = -1; ++ goto out; ++ } ++ ++ if (ieee->state != IEEE80211_LINKED && ++ ieee->state != IEEE80211_LINKED_SCANNING && ++ ieee->ssid_set == 0){ ++ ret = -1; ++ goto out; ++ } ++ len = ieee->current_network.ssid_len; ++ wrqu->essid.length = len; ++ strncpy(b,ieee->current_network.ssid,len); ++ wrqu->essid.flags = 1; ++ ++out: ++ spin_unlock_irqrestore(&ieee->lock, flags); ++ ++ return ret; ++ ++} ++ ++int ieee80211_wx_set_rate(struct ieee80211_device *ieee, ++ struct iw_request_info *info, ++ union iwreq_data *wrqu, char *extra) ++{ ++ ++ u32 target_rate = wrqu->bitrate.value; ++ ++ ieee->rate = target_rate/100000; ++ //FIXME: we might want to limit rate also in management protocols. ++ return 0; ++} ++ ++ ++ ++int ieee80211_wx_get_rate(struct ieee80211_device *ieee, ++ struct iw_request_info *info, ++ union iwreq_data *wrqu, char *extra) ++{ ++ ++ wrqu->bitrate.value = ieee->rate * 100000; ++ ++ return 0; ++} ++ ++int ieee80211_wx_set_mode(struct ieee80211_device *ieee, struct iw_request_info *a, ++ union iwreq_data *wrqu, char *b) ++{ ++ ++ ieee->sync_scan_hurryup = 1; ++ ++ down(&ieee->wx_sem); ++ //printk("=======>%s\n", __func__); ++ ++ if (wrqu->mode == ieee->iw_mode) ++ goto out; ++ ++ if (wrqu->mode == IW_MODE_MONITOR){ ++ ++ ieee->dev->type = ARPHRD_IEEE80211; ++ }else{ ++ ieee->dev->type = ARPHRD_ETHER; ++ } ++ ++ if (!ieee->proto_started){ ++ ieee->iw_mode = wrqu->mode; ++ }else{ ++ ieee80211_stop_protocol(ieee); ++ ieee->iw_mode = wrqu->mode; ++ ieee80211_start_protocol(ieee); ++ } ++ ++out: ++ up(&ieee->wx_sem); ++ return 0; ++} ++ ++#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,20) ++void ieee80211_wx_sync_scan_wq(struct work_struct *work) ++{ ++ struct ieee80211_device *ieee = container_of(work, struct ieee80211_device, wx_sync_scan_wq); ++#else ++void ieee80211_wx_sync_scan_wq(struct ieee80211_device *ieee) ++{ ++#endif ++ short chan; ++ ++ chan = ieee->current_network.channel; ++ ++ netif_carrier_off(ieee->dev); ++ ++ if (ieee->data_hard_stop) ++ ieee->data_hard_stop(ieee->dev); ++ ++ ieee80211_stop_send_beacons(ieee); ++ ++ ieee->state = IEEE80211_LINKED_SCANNING; ++ ieee->link_change(ieee->dev); ++ ++ ieee80211_start_scan_syncro(ieee); ++ ++ ieee->set_chan(ieee->dev, chan); ++ ++ ieee->state = IEEE80211_LINKED; ++ ieee->link_change(ieee->dev); ++ ++ if (ieee->data_hard_resume) ++ ieee->data_hard_resume(ieee->dev); ++ ++ if(ieee->iw_mode == IW_MODE_ADHOC || ieee->iw_mode == IW_MODE_MASTER) ++ ieee80211_start_send_beacons(ieee); ++ ++ netif_carrier_on(ieee->dev); ++ ++ up(&ieee->wx_sem); ++ ++} ++ ++int ieee80211_wx_set_scan(struct ieee80211_device *ieee, struct iw_request_info *a, ++ union iwreq_data *wrqu, char *b) ++{ ++ int ret = 0; ++ ++ down(&ieee->wx_sem); ++ ++ if (ieee->iw_mode == IW_MODE_MONITOR || !(ieee->proto_started)){ ++ ret = -1; ++ goto out; ++ } ++ ++ if ( ieee->state == IEEE80211_LINKED){ ++#if LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0) ++ queue_work(ieee->wq, &ieee->wx_sync_scan_wq); ++#else ++ schedule_task(&ieee->wx_sync_scan_wq); ++#endif ++ /* intentionally forget to up sem */ ++ return 0; ++ } ++ ++out: ++ up(&ieee->wx_sem); ++ return ret; ++} ++ ++int ieee80211_wx_set_essid(struct ieee80211_device *ieee, ++ struct iw_request_info *a, ++ union iwreq_data *wrqu, char *extra) ++{ ++ ++ int ret=0,len; ++ short proto_started; ++ unsigned long flags; ++ ++ ieee->sync_scan_hurryup = 1; ++ ++ down(&ieee->wx_sem); ++ ++ //printk("=======>%s\n", __func__); ++ proto_started = ieee->proto_started; ++ ++ if (wrqu->essid.length > IW_ESSID_MAX_SIZE){ ++ ret= -E2BIG; ++ goto out; ++ } ++ ++ if (ieee->iw_mode == IW_MODE_MONITOR){ ++ ret= -1; ++ goto out; ++ } ++ ++ if(proto_started){ ++ ieee80211_stop_protocol(ieee); ++ } ++ ++ /* this is just to be sure that the GET wx callback ++ * has consisten infos. not needed otherwise ++ */ ++ spin_lock_irqsave(&ieee->lock, flags); ++ ++ if (wrqu->essid.flags && wrqu->essid.length) { ++ len = ((wrqu->essid.length-1) < IW_ESSID_MAX_SIZE) ? (wrqu->essid.length-1) : IW_ESSID_MAX_SIZE; ++#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,20) ++ strncpy(ieee->current_network.ssid, extra, len); ++ ieee->current_network.ssid_len = len; ++#else ++ strncpy(ieee->current_network.ssid, extra, len+1); ++ ieee->current_network.ssid_len = len+1; ++#endif ++ ieee->ssid_set = 1; ++ //YJ,add,080819,for hidden ap ++ if(len == 0){ ++ memset(ieee->current_network.bssid, 0, ETH_ALEN); ++ ieee->current_network.capability = 0; ++ } ++ //YJ,add,080819,for hidden ap,end ++ } ++ else{ ++ ieee->ssid_set = 0; ++ ieee->current_network.ssid[0] = '\0'; ++ ieee->current_network.ssid_len = 0; ++ } ++ ++ spin_unlock_irqrestore(&ieee->lock, flags); ++ ++ if (proto_started){ ++ ieee80211_start_protocol(ieee); ++ } ++out: ++ up(&ieee->wx_sem); ++ return ret; ++} ++ ++ int ieee80211_wx_get_mode(struct ieee80211_device *ieee, struct iw_request_info *a, ++ union iwreq_data *wrqu, char *b) ++{ ++ ++ wrqu->mode = ieee->iw_mode; ++ return 0; ++} ++ ++ int ieee80211_wx_set_rawtx(struct ieee80211_device *ieee, ++ struct iw_request_info *info, ++ union iwreq_data *wrqu, char *extra) ++{ ++ ++ int *parms = (int *)extra; ++ int enable = (parms[0] > 0); ++ short prev = ieee->raw_tx; ++ ++ down(&ieee->wx_sem); ++ ++ if(enable) ++ ieee->raw_tx = 1; ++ else ++ ieee->raw_tx = 0; ++ ++ printk(KERN_INFO"raw TX is %s\n", ++ ieee->raw_tx ? "enabled" : "disabled"); ++ ++ if(ieee->iw_mode == IW_MODE_MONITOR) ++ { ++ if(prev == 0 && ieee->raw_tx){ ++ if (ieee->data_hard_resume) ++ ieee->data_hard_resume(ieee->dev); ++ ++ netif_carrier_on(ieee->dev); ++ } ++ ++ if(prev && ieee->raw_tx == 1) ++ netif_carrier_off(ieee->dev); ++ } ++ ++ up(&ieee->wx_sem); ++ ++ return 0; ++} ++ ++int ieee80211_wx_get_name(struct ieee80211_device *ieee, ++ struct iw_request_info *info, ++ union iwreq_data *wrqu, char *extra) ++{ ++ strcpy(wrqu->name, "802.11"); ++ if(ieee->modulation & IEEE80211_CCK_MODULATION){ ++ strcat(wrqu->name, "b"); ++ if(ieee->modulation & IEEE80211_OFDM_MODULATION) ++ strcat(wrqu->name, "/g"); ++ }else if(ieee->modulation & IEEE80211_OFDM_MODULATION) ++ strcat(wrqu->name, "g"); ++ ++ if((ieee->state == IEEE80211_LINKED) || ++ (ieee->state == IEEE80211_LINKED_SCANNING)) ++ strcat(wrqu->name," linked"); ++ else if(ieee->state != IEEE80211_NOLINK) ++ strcat(wrqu->name," link.."); ++ ++ ++ return 0; ++} ++ ++ ++/* this is mostly stolen from hostap */ ++int ieee80211_wx_set_power(struct ieee80211_device *ieee, ++ struct iw_request_info *info, ++ union iwreq_data *wrqu, char *extra) ++{ ++ int ret = 0; ++ ++ if( ++ (!ieee->sta_wake_up) || ++ (!ieee->ps_request_tx_ack) || ++ (!ieee->enter_sleep_state) || ++ (!ieee->ps_is_queue_empty)){ ++ ++ printk("ERROR. PS mode is tryied to be use but\ ++driver missed a callback\n\n"); ++ ++ return -1; ++ } ++ ++ down(&ieee->wx_sem); ++ ++ if (wrqu->power.disabled){ ++ ieee->ps = IEEE80211_PS_DISABLED; ++ ++ goto exit; ++ } ++ switch (wrqu->power.flags & IW_POWER_MODE) { ++ case IW_POWER_UNICAST_R: ++ ieee->ps = IEEE80211_PS_UNICAST; ++ ++ break; ++ case IW_POWER_ALL_R: ++ ieee->ps = IEEE80211_PS_UNICAST | IEEE80211_PS_MBCAST; ++ break; ++ ++ case IW_POWER_ON: ++ ieee->ps = IEEE80211_PS_DISABLED; ++ break; ++ ++ default: ++ ret = -EINVAL; ++ goto exit; ++ } ++ ++ if (wrqu->power.flags & IW_POWER_TIMEOUT) { ++ ++ ieee->ps_timeout = wrqu->power.value / 1000; ++ printk("Timeout %d\n",ieee->ps_timeout); ++ } ++ ++ if (wrqu->power.flags & IW_POWER_PERIOD) { ++ ++ ret = -EOPNOTSUPP; ++ goto exit; ++ //wrq->value / 1024; ++ ++ } ++exit: ++ up(&ieee->wx_sem); ++ return ret; ++ ++} ++ ++/* this is stolen from hostap */ ++int ieee80211_wx_get_power(struct ieee80211_device *ieee, ++ struct iw_request_info *info, ++ union iwreq_data *wrqu, char *extra) ++{ ++ int ret =0; ++ ++ down(&ieee->wx_sem); ++ ++ if(ieee->ps == IEEE80211_PS_DISABLED){ ++ wrqu->power.disabled = 1; ++ goto exit; ++ } ++ ++ wrqu->power.disabled = 0; ++ ++// if ((wrqu->power.flags & IW_POWER_TYPE) == IW_POWER_TIMEOUT) { ++ wrqu->power.flags = IW_POWER_TIMEOUT; ++ wrqu->power.value = ieee->ps_timeout * 1000; ++// } else { ++// ret = -EOPNOTSUPP; ++// goto exit; ++ //wrqu->power.flags = IW_POWER_PERIOD; ++ //wrqu->power.value = ieee->current_network.dtim_period * ++ // ieee->current_network.beacon_interval * 1024; ++// } ++ ++ ++ if (ieee->ps & IEEE80211_PS_MBCAST) ++ wrqu->power.flags |= IW_POWER_ALL_R; ++ else ++ wrqu->power.flags |= IW_POWER_UNICAST_R; ++ ++exit: ++ up(&ieee->wx_sem); ++ return ret; ++ ++} ++#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0)) ++EXPORT_SYMBOL(ieee80211_wx_get_essid); ++EXPORT_SYMBOL(ieee80211_wx_set_essid); ++EXPORT_SYMBOL(ieee80211_wx_set_rate); ++EXPORT_SYMBOL(ieee80211_wx_get_rate); ++EXPORT_SYMBOL(ieee80211_wx_set_wap); ++EXPORT_SYMBOL(ieee80211_wx_get_wap); ++EXPORT_SYMBOL(ieee80211_wx_set_mode); ++EXPORT_SYMBOL(ieee80211_wx_get_mode); ++EXPORT_SYMBOL(ieee80211_wx_set_scan); ++EXPORT_SYMBOL(ieee80211_wx_get_freq); ++EXPORT_SYMBOL(ieee80211_wx_set_freq); ++EXPORT_SYMBOL(ieee80211_wx_set_rawtx); ++EXPORT_SYMBOL(ieee80211_wx_get_name); ++EXPORT_SYMBOL(ieee80211_wx_set_power); ++EXPORT_SYMBOL(ieee80211_wx_get_power); ++EXPORT_SYMBOL(ieee80211_wlan_frequencies); ++#else ++EXPORT_SYMBOL_NOVERS(ieee80211_wx_get_essid); ++EXPORT_SYMBOL_NOVERS(ieee80211_wx_set_essid); ++EXPORT_SYMBOL_NOVERS(ieee80211_wx_set_rate); ++EXPORT_SYMBOL_NOVERS(ieee80211_wx_get_rate); ++EXPORT_SYMBOL_NOVERS(ieee80211_wx_set_wap); ++EXPORT_SYMBOL_NOVERS(ieee80211_wx_get_wap); ++EXPORT_SYMBOL_NOVERS(ieee80211_wx_set_mode); ++EXPORT_SYMBOL_NOVERS(ieee80211_wx_get_mode); ++EXPORT_SYMBOL_NOVERS(ieee80211_wx_set_scan); ++EXPORT_SYMBOL_NOVERS(ieee80211_wx_get_freq); ++EXPORT_SYMBOL_NOVERS(ieee80211_wx_set_freq); ++EXPORT_SYMBOL_NOVERS(ieee80211_wx_set_rawtx); ++EXPORT_SYMBOL_NOVERS(ieee80211_wx_get_name); ++EXPORT_SYMBOL_NOVERS(ieee80211_wx_set_power); ++EXPORT_SYMBOL_NOVERS(ieee80211_wx_get_power); ++EXPORT_SYMBOL_NOVERS(ieee80211_wlan_frequencies); ++#endif +diff -Nur linux-2.6.33/drivers/net/wireless/rtl8187b/ieee80211/ieee80211_tx.c linux-lemote/drivers/net/wireless/rtl8187b/ieee80211/ieee80211_tx.c +--- linux-2.6.33/drivers/net/wireless/rtl8187b/ieee80211/ieee80211_tx.c 1970-01-01 01:00:00.000000000 +0100 ++++ linux-lemote/drivers/net/wireless/rtl8187b/ieee80211/ieee80211_tx.c 2010-03-06 16:43:22.000000000 +0100 +@@ -0,0 +1,876 @@ ++/****************************************************************************** ++ ++ Copyright(c) 2003 - 2004 Intel Corporation. All rights reserved. ++ ++ This program is free software; you can redistribute it and/or modify it ++ under the terms of version 2 of the GNU General Public License as ++ published by the Free Software Foundation. ++ ++ 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. ++ ++ The full GNU General Public License is included in this distribution in the ++ file called LICENSE. ++ ++ Contact Information: ++ James P. Ketrenos <ipw2100-admin@linux.intel.com> ++ Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 ++ ++****************************************************************************** ++ ++ Few modifications for Realtek's Wi-Fi drivers by ++ Andrea Merello <andreamrl@tiscali.it> ++ ++ A special thanks goes to Realtek for their support ! ++ ++******************************************************************************/ ++ ++#include <linux/compiler.h> ++//#include <linux/config.h> ++#include <linux/errno.h> ++#include <linux/if_arp.h> ++#include <linux/in6.h> ++#include <linux/in.h> ++#include <linux/ip.h> ++#include <linux/kernel.h> ++#include <linux/module.h> ++#include <linux/netdevice.h> ++#include <linux/pci.h> ++#include <linux/proc_fs.h> ++#include <linux/skbuff.h> ++#include <linux/slab.h> ++#include <linux/tcp.h> ++#include <linux/types.h> ++#include <linux/version.h> ++#include <linux/wireless.h> ++#include <linux/etherdevice.h> ++#include <asm/uaccess.h> ++#include <linux/if_vlan.h> ++ ++#include "ieee80211.h" ++ ++ ++/* ++ ++ ++802.11 Data Frame ++ ++ ++802.11 frame_contorl for data frames - 2 bytes ++ ,-----------------------------------------------------------------------------------------. ++bits | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | a | b | c | d | e | ++ |----|-----|-----|-----|-----|-----|-----|-----|-----|-----|-----|-----|-----|-----|------| ++val | 0 | 0 | 0 | 1 | x | 0 | 0 | 0 | 1 | 0 | x | x | x | x | x | ++ |----|-----|-----|-----|-----|-----|-----|-----|-----|-----|-----|-----|-----|-----|------| ++desc | ^-ver-^ | ^type-^ | ^-----subtype-----^ | to |from |more |retry| pwr |more |wep | ++ | | | x=0 data,x=1 data+ack | DS | DS |frag | | mgm |data | | ++ '-----------------------------------------------------------------------------------------' ++ /\ ++ | ++802.11 Data Frame | ++ ,--------- 'ctrl' expands to >-----------' ++ | ++ ,--'---,-------------------------------------------------------------. ++Bytes | 2 | 2 | 6 | 6 | 6 | 2 | 0..2312 | 4 | ++ |------|------|---------|---------|---------|------|---------|------| ++Desc. | ctrl | dura | DA/RA | TA | SA | Sequ | Frame | fcs | ++ | | tion | (BSSID) | | | ence | data | | ++ `--------------------------------------------------| |------' ++Total: 28 non-data bytes `----.----' ++ | ++ .- 'Frame data' expands to <---------------------------' ++ | ++ V ++ ,---------------------------------------------------. ++Bytes | 1 | 1 | 1 | 3 | 2 | 0-2304 | ++ |------|------|---------|----------|------|---------| ++Desc. | SNAP | SNAP | Control |Eth Tunnel| Type | IP | ++ | DSAP | SSAP | | | | Packet | ++ | 0xAA | 0xAA |0x03 (UI)|0x00-00-F8| | | ++ `-----------------------------------------| | ++Total: 8 non-data bytes `----.----' ++ | ++ .- 'IP Packet' expands, if WEP enabled, to <--' ++ | ++ V ++ ,-----------------------. ++Bytes | 4 | 0-2296 | 4 | ++ |-----|-----------|-----| ++Desc. | IV | Encrypted | ICV | ++ | | IP Packet | | ++ `-----------------------' ++Total: 8 non-data bytes ++ ++ ++802.3 Ethernet Data Frame ++ ++ ,-----------------------------------------. ++Bytes | 6 | 6 | 2 | Variable | 4 | ++ |-------|-------|------|-----------|------| ++Desc. | Dest. | Source| Type | IP Packet | fcs | ++ | MAC | MAC | | | | ++ `-----------------------------------------' ++Total: 18 non-data bytes ++ ++In the event that fragmentation is required, the incoming payload is split into ++N parts of size ieee->fts. The first fragment contains the SNAP header and the ++remaining packets are just data. ++ ++If encryption is enabled, each fragment payload size is reduced by enough space ++to add the prefix and postfix (IV and ICV totalling 8 bytes in the case of WEP) ++So if you have 1500 bytes of payload with ieee->fts set to 500 without ++encryption it will take 3 frames. With WEP it will take 4 frames as the ++payload of each frame is reduced to 492 bytes. ++ ++* SKB visualization ++* ++* ,- skb->data ++* | ++* | ETHERNET HEADER ,-<-- PAYLOAD ++* | | 14 bytes from skb->data ++* | 2 bytes for Type --> ,T. | (sizeof ethhdr) ++* | | | | ++* |,-Dest.--. ,--Src.---. | | | ++* | 6 bytes| | 6 bytes | | | | ++* v | | | | | | ++* 0 | v 1 | v | v 2 ++* 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 ++* ^ | ^ | ^ | ++* | | | | | | ++* | | | | `T' <---- 2 bytes for Type ++* | | | | ++* | | '---SNAP--' <-------- 6 bytes for SNAP ++* | | ++* `-IV--' <-------------------- 4 bytes for IV (WEP) ++* ++* SNAP HEADER ++* ++*/ ++ ++static u8 P802_1H_OUI[P80211_OUI_LEN] = { 0x00, 0x00, 0xf8 }; ++static u8 RFC1042_OUI[P80211_OUI_LEN] = { 0x00, 0x00, 0x00 }; ++ ++static inline int ieee80211_put_snap(u8 *data, u16 h_proto) ++{ ++ struct ieee80211_snap_hdr *snap; ++ u8 *oui; ++ ++ snap = (struct ieee80211_snap_hdr *)data; ++ snap->dsap = 0xaa; ++ snap->ssap = 0xaa; ++ snap->ctrl = 0x03; ++ ++ if (h_proto == 0x8137 || h_proto == 0x80f3) ++ oui = P802_1H_OUI; ++ else ++ oui = RFC1042_OUI; ++ snap->oui[0] = oui[0]; ++ snap->oui[1] = oui[1]; ++ snap->oui[2] = oui[2]; ++ ++ *(u16 *)(data + SNAP_SIZE) = htons(h_proto); ++ ++ return SNAP_SIZE + sizeof(u16); ++} ++ ++int ieee80211_encrypt_fragment( ++ struct ieee80211_device *ieee, ++ struct sk_buff *frag, ++ int hdr_len) ++{ ++ struct ieee80211_crypt_data* crypt = NULL;//ieee->crypt[ieee->tx_keyidx]; ++ int res;//, i; ++// printk("====>wwwwww%s():ieee:%x, hdr_len:%d\n", __FUNCTION__, ieee, hdr_len); ++/* printk("\n%s(), hdr_len:%d\n", __FUNCTION__, hdr_len); ++ for (i = 0; i < 48; i++) { ++ if (i % 16 == 0) printk("\n\t"); ++ printk("%2x ", *(frag->data+i)); ++ } ++*/ ++ ++#ifdef _RTL8187_EXT_PATCH_ ++#if 0 ++ i = ieee80211_find_MP(ieee, ((struct ieee80211_hdr*) frag->data)->addr1); ++ if (i== -1){ ++ printk("error find MP entry in %s()\n", __FUNCTION__); ++ return i; ++ } ++ // printk("%s():"MAC_FMT", find in index:%d\n", __FUNCTION__, MAC_ARG(((struct ieee80211_hdr*)frag->data)->addr1), i); ++#endif ++// crypt = ieee->cryptlist[MAX_MP-1]->crypt[ieee->tx_keyidx]; ++ crypt = ieee->cryptlist[0]->crypt[ieee->tx_keyidx]; ++#else ++ crypt = ieee->crypt[ieee->tx_keyidx]; ++#endif ++ /*added to care about null crypt condition, to solve that system hangs when shared keys error*/ ++ if (!crypt || !crypt->ops) ++ return -1; ++ ++#ifdef CONFIG_IEEE80211_CRYPT_TKIP ++ struct ieee80211_hdr *header; ++ ++ if (ieee->tkip_countermeasures && ++ crypt && crypt->ops && strcmp(crypt->ops->name, "TKIP") == 0) { ++ header = (struct ieee80211_hdr *) frag->data; ++ if (net_ratelimit()) { ++ printk(KERN_DEBUG "%s: TKIP countermeasures: dropped " ++ "TX packet to " MAC_FMT "\n", ++ ieee->dev->name, MAC_ARG(header->addr1)); ++ } ++ return -1; ++ } ++#endif ++ /* To encrypt, frame format is: ++ * IV (4 bytes), clear payload (including SNAP), ICV (4 bytes) */ ++ ++ // PR: FIXME: Copied from hostap. Check fragmentation/MSDU/MPDU encryption. ++ /* Host-based IEEE 802.11 fragmentation for TX is not yet supported, so ++ * call both MSDU and MPDU encryption functions from here. */ ++ atomic_inc(&crypt->refcnt); ++ res = 0; ++ if (crypt->ops->encrypt_msdu) ++ res = crypt->ops->encrypt_msdu(frag, hdr_len, crypt->priv); ++ if (res == 0 && crypt->ops->encrypt_mpdu) ++ res = crypt->ops->encrypt_mpdu(frag, hdr_len, crypt->priv); ++ atomic_dec(&crypt->refcnt); ++ if (res < 0) { ++ printk(KERN_INFO "%s: Encryption failed: len=%d.\n", ++ ieee->dev->name, frag->len); ++ ieee->ieee_stats.tx_discards++; ++ return -1; ++ } ++ ++ return 0; ++} ++ ++ ++void ieee80211_txb_free(struct ieee80211_txb *txb) { ++ int i; ++ if (unlikely(!txb)) ++ return; ++ for (i = 0; i < txb->nr_frags; i++) ++ if (txb->fragments[i]) ++ dev_kfree_skb_any(txb->fragments[i]); ++ kfree(txb); ++} ++ ++struct ieee80211_txb *ieee80211_alloc_txb(int nr_frags, int txb_size, ++ int gfp_mask) ++{ ++ struct ieee80211_txb *txb; ++ int i; ++ txb = kmalloc( ++ sizeof(struct ieee80211_txb) + (sizeof(u8*) * nr_frags), ++ gfp_mask); ++ if (!txb) ++ return NULL; ++ ++ memset(txb, 0, sizeof(struct ieee80211_txb)); ++ txb->nr_frags = nr_frags; ++ txb->frag_size = txb_size; ++ ++ for (i = 0; i < nr_frags; i++) { ++ txb->fragments[i] = dev_alloc_skb(txb_size); ++ if (unlikely(!txb->fragments[i])) { ++ i--; ++ break; ++ } ++ } ++ if (unlikely(i != nr_frags)) { ++ while (i >= 0) ++ dev_kfree_skb_any(txb->fragments[i--]); ++ kfree(txb); ++ return NULL; ++ } ++ return txb; ++} ++ ++// Classify the to-be send data packet ++// Need to acquire the sent queue index. ++static int ++ieee80211_classify(struct sk_buff *skb, struct ieee80211_network *network) ++{ ++ struct ether_header *eh = (struct ether_header*)skb->data; ++ unsigned int wme_UP = 0; ++ ++ if(!network->QoS_Enable) { ++ skb->priority = 0; ++ return(wme_UP); ++ } ++ ++ if(eh->ether_type == __constant_htons(ETHERTYPE_IP)) { ++ const struct iphdr *ih = (struct iphdr*)(skb->data + \ ++ sizeof(struct ether_header)); ++ wme_UP = (ih->tos >> 5)&0x07; ++ } else if (vlan_tx_tag_present(skb)) {//vtag packet ++#ifndef VLAN_PRI_SHIFT ++#define VLAN_PRI_SHIFT 13 /* Shift to find VLAN user priority */ ++#define VLAN_PRI_MASK 7 /* Mask for user priority bits in VLAN */ ++#endif ++ u32 tag = vlan_tx_tag_get(skb); ++ wme_UP = (tag >> VLAN_PRI_SHIFT) & VLAN_PRI_MASK; ++ } else if(ETH_P_PAE == ntohs(((struct ethhdr *)skb->data)->h_proto)) { ++ //printk(KERN_WARNING "type = normal packet\n"); ++ wme_UP = 7; ++ } ++ skb->priority = wme_UP; ++/* ++ if (network->QoS_Enable) { ++ skb->priority = wme_UP; ++ }else { ++ skb->priority = 0; ++ } ++*/ ++ return(wme_UP); ++} ++ ++#ifdef _RTL8187_EXT_PATCH_ ++// based on part of ieee80211_xmit. Mainly allocate txb. ieee->lock is held ++struct ieee80211_txb *ieee80211_ext_alloc_txb(struct sk_buff *skb, struct net_device *dev, struct ieee80211_hdr_3addr *header, int hdr_len, u8 isQoS, u16 *pQOS_ctl, int isEncrypt, struct ieee80211_crypt_data* crypt) ++{ ++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0)) ++ struct ieee80211_device *ieee = netdev_priv(dev); ++#else ++ struct ieee80211_device *ieee = (struct ieee80211_device *)dev->priv; ++#endif ++ struct ieee80211_txb *txb = NULL; ++ struct ieee80211_hdr_3addr *frag_hdr; ++ int i, bytes_per_frag, nr_frags, bytes_last_frag, frag_size; ++ int ether_type; ++ int bytes, QOS_ctl; ++ struct sk_buff *skb_frag; ++ ++ ether_type = ntohs(((struct ethhdr *)skb->data)->h_proto); ++ ++ /* Advance the SKB to the start of the payload */ ++ skb_pull(skb, sizeof(struct ethhdr)); ++ ++ /* Determine total amount of storage required for TXB packets */ ++ bytes = skb->len + SNAP_SIZE + sizeof(u16); ++ ++ /* Determine fragmentation size based on destination (multicast ++ * and broadcast are not fragmented) */ ++ // if (is_multicast_ether_addr(dest) || ++ // is_broadcast_ether_addr(dest)) { ++ if (is_multicast_ether_addr(header->addr1) || ++ is_broadcast_ether_addr(header->addr1)) { ++ frag_size = MAX_FRAG_THRESHOLD; ++ QOS_ctl = QOS_CTL_NOTCONTAIN_ACK; ++ } ++ else { ++ //printk(KERN_WARNING "&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&frag_size = %d\n", frag_size); ++ frag_size = ieee->fts;//default:392 ++ QOS_ctl = 0; ++ } ++ ++ if(isQoS) { ++ QOS_ctl |= skb->priority; //set in the ieee80211_classify ++ *pQOS_ctl = cpu_to_le16(QOS_ctl); ++ } ++ //printk(KERN_WARNING "header size = %d, QOS_ctl = %x\n", hdr_len,QOS_ctl); ++ /* Determine amount of payload per fragment. Regardless of if ++ * this stack is providing the full 802.11 header, one will ++ * eventually be affixed to this fragment -- so we must account for ++ * it when determining the amount of payload space. */ ++ //bytes_per_frag = frag_size - (IEEE80211_3ADDR_LEN + (ieee->current_network->QoS_Enable ? 2:0)); ++ bytes_per_frag = frag_size - hdr_len; ++ if (ieee->config & ++ (CFG_IEEE80211_COMPUTE_FCS | CFG_IEEE80211_RESERVE_FCS)) ++ bytes_per_frag -= IEEE80211_FCS_LEN; ++ ++ /* Each fragment may need to have room for encryptiong pre/postfix */ ++ if (isEncrypt) ++ bytes_per_frag -= crypt->ops->extra_prefix_len + ++ crypt->ops->extra_postfix_len; ++ ++ /* Number of fragments is the total bytes_per_frag / ++ * payload_per_fragment */ ++ nr_frags = bytes / bytes_per_frag; ++ bytes_last_frag = bytes % bytes_per_frag; ++ if (bytes_last_frag) ++ nr_frags++; ++ else ++ bytes_last_frag = bytes_per_frag; ++ ++ /* When we allocate the TXB we allocate enough space for the reserve ++ * and full fragment bytes (bytes_per_frag doesn't include prefix, ++ * postfix, header, FCS, etc.) */ ++ txb = ieee80211_alloc_txb(nr_frags, frag_size, GFP_ATOMIC); ++ if (unlikely(!txb)) { ++ printk(KERN_WARNING "%s: Could not allocate TXB\n", ++ ieee->dev->name); ++ return NULL; ++ } ++ txb->encrypted = isEncrypt; ++ txb->payload_size = bytes; ++ ++ for (i = 0; i < nr_frags; i++) { ++ skb_frag = txb->fragments[i]; ++ skb_frag->priority = UP2AC(skb->priority); ++ if (isEncrypt) ++ skb_reserve(skb_frag, crypt->ops->extra_prefix_len); ++ ++ frag_hdr = (struct ieee80211_hdr_3addr *)skb_put(skb_frag, hdr_len); ++ memcpy(frag_hdr, (void *)header, hdr_len); ++ ++ /* If this is not the last fragment, then add the MOREFRAGS ++ * bit to the frame control */ ++ if (i != nr_frags - 1) { ++ frag_hdr->frame_ctl = cpu_to_le16( ++ header->frame_ctl | IEEE80211_FCTL_MOREFRAGS); ++ bytes = bytes_per_frag; ++ ++ } else { ++ /* The last fragment takes the remaining length */ ++ bytes = bytes_last_frag; ++ } ++ ++ frag_hdr->seq_ctl = cpu_to_le16(ieee->seq_ctrl[0]<<4 | i); ++ //frag_hdr->seq_ctl = cpu_to_le16(ieee->seq_ctrl<<4 | i); ++ // ++ ++ /* Put a SNAP header on the first fragment */ ++ if (i == 0) { ++ ieee80211_put_snap( ++ skb_put(skb_frag, SNAP_SIZE + sizeof(u16)), ether_type); ++ bytes -= SNAP_SIZE + sizeof(u16); ++ } ++ ++ memcpy(skb_put(skb_frag, bytes), skb->data, bytes); ++ ++ /* Advance the SKB... */ ++ skb_pull(skb, bytes); ++ ++ /* Encryption routine will move the header forward in order ++ * to insert the IV between the header and the payload */ ++ if (isEncrypt) ++ ieee80211_encrypt_fragment(ieee, skb_frag, hdr_len); ++ if (ieee->config & ++ (CFG_IEEE80211_COMPUTE_FCS | CFG_IEEE80211_RESERVE_FCS)) ++ skb_put(skb_frag, 4); ++ } ++ // Advance sequence number in data frame. ++ //printk(KERN_WARNING "QoS Enalbed? %s\n", ieee->current_network.QoS_Enable?"Y":"N"); ++ if (ieee->seq_ctrl[0] == 0xFFF) ++ ieee->seq_ctrl[0] = 0; ++ else ++ ieee->seq_ctrl[0]++; ++ // stanley, just for debug ++/* ++{ ++ int j=0; ++ for(j=0;j<nr_frags;j++) ++ { ++ int i; ++ struct sk_buff *skb = txb->fragments[j]; ++ printk("send(%d): ", j); ++ for (i=0;i<skb->len;i++) ++ printk("%02X ", skb->data[i]&0xff); ++ printk("\n"); ++ } ++} ++*/ ++ ++ return txb; ++} ++ ++ ++// based on part of ieee80211_xmit. Mainly allocate txb. ieee->lock is held ++// Assume no encryption, no FCS computing ++struct ieee80211_txb *ieee80211_ext_reuse_txb(struct sk_buff *skb, struct net_device *dev, struct ieee80211_hdr_3addr *header, int hdr_len, u8 isQoS, u16 *pQOS_ctl, int isEncrypt, struct ieee80211_crypt_data* crypt) ++{ ++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0)) ++ struct ieee80211_device *ieee = netdev_priv(dev); ++#else ++ struct ieee80211_device *ieee = (struct ieee80211_device *)dev->priv; ++#endif ++ struct ieee80211_txb *txb = NULL; ++ struct ieee80211_hdr_3addr *frag_hdr; ++ int ether_type; ++ int bytes, QOS_ctl; ++ ++ ether_type = ntohs(((struct ethhdr *)skb->data)->h_proto); ++ ++ /* Advance the SKB to the start of the payload */ ++ skb_pull(skb, sizeof(struct ethhdr)); ++ ++ /* Determine total amount of storage required for TXB packets */ ++ bytes = skb->len + SNAP_SIZE + sizeof(u16); ++ ++ if (is_multicast_ether_addr(header->addr1) || ++ is_broadcast_ether_addr(header->addr1)) { ++ QOS_ctl = QOS_CTL_NOTCONTAIN_ACK; ++ } ++ else { ++ QOS_ctl = 0; ++ } ++ ++ if(isQoS) { ++ QOS_ctl |= skb->priority; //set in the ieee80211_classify ++ *pQOS_ctl = cpu_to_le16(QOS_ctl); ++ } ++ ++ txb = kmalloc( sizeof(struct ieee80211_txb) + sizeof(u8*), GFP_ATOMIC ); ++ if (unlikely(!txb)) { ++ printk(KERN_WARNING "%s: Could not allocate TXB\n", ++ ieee->dev->name); ++ return NULL; ++ } ++ ++ txb->nr_frags = 1; ++ txb->frag_size = bytes; ++ txb->encrypted = isEncrypt; ++ txb->payload_size = bytes; ++ ++ txb->fragments[0] = skb; ++ ieee80211_put_snap( ++ skb_push(skb, SNAP_SIZE + sizeof(u16)), ether_type); ++ frag_hdr = (struct ieee80211_hdr_3addr *)skb_push(skb, hdr_len); ++ memcpy(frag_hdr, (void *)header, hdr_len); ++ frag_hdr->seq_ctl = cpu_to_le16(ieee->seq_ctrl[0]<<4 | 0); ++ skb->priority = UP2AC(skb->priority); ++ if(isEncrypt) ++ ieee80211_encrypt_fragment(ieee,skb,hdr_len); ++ ++ // Advance sequence number in data frame. ++ //printk(KERN_WARNING "QoS Enalbed? %s\n", ieee->current_network.QoS_Enable?"Y":"N"); ++ if (ieee->seq_ctrl[0] == 0xFFF) ++ ieee->seq_ctrl[0] = 0; ++ else ++ ieee->seq_ctrl[0]++; ++ ++ return txb; ++} ++ ++#endif // _RTL8187_EXT_PATCH_ ++ ++/* SKBs are added to the ieee->tx_queue. */ ++int ieee80211_xmit(struct sk_buff *skb, ++ struct net_device *dev) ++{ ++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0)) ++ struct ieee80211_device *ieee = netdev_priv(dev); ++#else ++ struct ieee80211_device *ieee = (struct ieee80211_device *)dev->priv; ++#endif ++ struct ieee80211_txb *txb = NULL; ++ struct ieee80211_hdr_3addr_QOS *frag_hdr; ++ int i, bytes_per_frag, nr_frags, bytes_last_frag, frag_size; ++ unsigned long flags; ++ struct net_device_stats *stats = &ieee->stats; ++ int ether_type, encrypt; ++ int bytes, fc, QOS_ctl, hdr_len; ++ struct sk_buff *skb_frag; ++ //struct ieee80211_hdr header = { /* Ensure zero initialized */ ++ // .duration_id = 0, ++ // .seq_ctl = 0 ++ //}; ++ struct ieee80211_hdr_3addr_QOS header = { /* Ensure zero initialized */ ++ .duration_id = 0, ++ .seq_ctl = 0, ++ .QOS_ctl = 0 ++ }; ++ u8 dest[ETH_ALEN], src[ETH_ALEN]; ++ ++ struct ieee80211_crypt_data* crypt; ++ ++ //printk(KERN_WARNING "upper layer packet!\n"); ++ spin_lock_irqsave(&ieee->lock, flags); ++ ++ /* If there is no driver handler to take the TXB, dont' bother ++ * creating it... */ ++ if ((!ieee->hard_start_xmit && !(ieee->softmac_features & IEEE_SOFTMAC_TX_QUEUE))|| ++ ((!ieee->softmac_data_hard_start_xmit && (ieee->softmac_features & IEEE_SOFTMAC_TX_QUEUE)))) { ++ printk(KERN_WARNING "%s: No xmit handler.\n", ++ ieee->dev->name); ++ goto success; ++ } ++ ++ ieee80211_classify(skb,&ieee->current_network); ++ if(likely(ieee->raw_tx == 0)){ ++ ++ if (unlikely(skb->len < SNAP_SIZE + sizeof(u16))) { ++ printk(KERN_WARNING "%s: skb too small (%d).\n", ++ ieee->dev->name, skb->len); ++ goto success; ++ } ++ ++ ++#ifdef _RTL8187_EXT_PATCH_ ++ // note, skb->priority which was set by ieee80211_classify, and used by physical tx ++ if((ieee->iw_mode == ieee->iw_ext_mode) && (ieee->ext_patch_ieee80211_xmit)) ++ { ++ txb = ieee->ext_patch_ieee80211_xmit(skb, dev); ++ goto success; ++ } ++#endif ++ ++ ether_type = ntohs(((struct ethhdr *)skb->data)->h_proto); ++#ifdef _RTL8187_EXT_PATCH_ ++ crypt = ieee->cryptlist[0]->crypt[ieee->tx_keyidx]; ++#else ++ crypt = ieee->crypt[ieee->tx_keyidx]; ++#endif ++ encrypt = !(ether_type == ETH_P_PAE && ieee->ieee802_1x) && ++ ieee->host_encrypt && crypt && crypt->ops; ++ ++ if (!encrypt && ieee->ieee802_1x && ++ ieee->drop_unencrypted && ether_type != ETH_P_PAE) { ++ stats->tx_dropped++; ++ goto success; ++ } ++ ++ #ifdef CONFIG_IEEE80211_DEBUG ++ if (crypt && !encrypt && ether_type == ETH_P_PAE) { ++ struct eapol *eap = (struct eapol *)(skb->data + ++ sizeof(struct ethhdr) - SNAP_SIZE - sizeof(u16)); ++ IEEE80211_DEBUG_EAP("TX: IEEE 802.11 EAPOL frame: %s\n", ++ eap_get_type(eap->type)); ++ } ++ #endif ++ ++ /* Save source and destination addresses */ ++ memcpy(&dest, skb->data, ETH_ALEN); ++ memcpy(&src, skb->data+ETH_ALEN, ETH_ALEN); ++ ++ /* Advance the SKB to the start of the payload */ ++ skb_pull(skb, sizeof(struct ethhdr)); ++ ++ /* Determine total amount of storage required for TXB packets */ ++ bytes = skb->len + SNAP_SIZE + sizeof(u16); ++ ++ if(ieee->current_network.QoS_Enable) { ++ if (encrypt) ++ fc = IEEE80211_FTYPE_DATA | IEEE80211_STYPE_QOS_DATA | ++ IEEE80211_FCTL_WEP; ++ else ++ fc = IEEE80211_FTYPE_DATA | IEEE80211_STYPE_QOS_DATA; ++ ++ } else { ++ if (encrypt) ++ fc = IEEE80211_FTYPE_DATA | IEEE80211_STYPE_DATA | ++ IEEE80211_FCTL_WEP; ++ else ++ fc = IEEE80211_FTYPE_DATA | IEEE80211_STYPE_DATA; ++ } ++ ++ if (ieee->iw_mode == IW_MODE_INFRA) { ++ fc |= IEEE80211_FCTL_TODS; ++ /* To DS: Addr1 = BSSID, Addr2 = SA, ++ Addr3 = DA */ ++ memcpy(&header.addr1, ieee->current_network.bssid, ETH_ALEN); ++ memcpy(&header.addr2, &src, ETH_ALEN); ++ memcpy(&header.addr3, &dest, ETH_ALEN); ++ } else if (ieee->iw_mode == IW_MODE_ADHOC) { ++ /* not From/To DS: Addr1 = DA, Addr2 = SA, ++ Addr3 = BSSID */ ++ memcpy(&header.addr1, dest, ETH_ALEN); ++ memcpy(&header.addr2, src, ETH_ALEN); ++ memcpy(&header.addr3, ieee->current_network.bssid, ETH_ALEN); ++ } ++ // printk(KERN_WARNING "essid MAC address is "MAC_FMT, MAC_ARG(&header.addr1)); ++ header.frame_ctl = cpu_to_le16(fc); ++ //hdr_len = IEEE80211_3ADDR_LEN; ++ ++ /* Determine fragmentation size based on destination (multicast ++ * and broadcast are not fragmented) */ ++// if (is_multicast_ether_addr(dest) || ++// is_broadcast_ether_addr(dest)) { ++ if (is_multicast_ether_addr(header.addr1) || ++ is_broadcast_ether_addr(header.addr1)) { ++ frag_size = MAX_FRAG_THRESHOLD; ++ QOS_ctl = QOS_CTL_NOTCONTAIN_ACK; ++ } ++ else { ++ //printk(KERN_WARNING "&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&frag_size = %d\n", frag_size); ++ frag_size = ieee->fts;//default:392 ++ QOS_ctl = 0; ++ } ++ ++ if (ieee->current_network.QoS_Enable) { ++ hdr_len = IEEE80211_3ADDR_LEN + 2; ++ QOS_ctl |= skb->priority; //set in the ieee80211_classify ++ header.QOS_ctl = cpu_to_le16(QOS_ctl); ++ } else { ++ hdr_len = IEEE80211_3ADDR_LEN; ++ } ++ //printk(KERN_WARNING "header size = %d, QOS_ctl = %x\n", hdr_len,QOS_ctl); ++ /* Determine amount of payload per fragment. Regardless of if ++ * this stack is providing the full 802.11 header, one will ++ * eventually be affixed to this fragment -- so we must account for ++ * it when determining the amount of payload space. */ ++ //bytes_per_frag = frag_size - (IEEE80211_3ADDR_LEN + (ieee->current_network->QoS_Enable ? 2:0)); ++ bytes_per_frag = frag_size - hdr_len; ++ if (ieee->config & ++ (CFG_IEEE80211_COMPUTE_FCS | CFG_IEEE80211_RESERVE_FCS)) ++ bytes_per_frag -= IEEE80211_FCS_LEN; ++ ++ /* Each fragment may need to have room for encryptiong pre/postfix */ ++ if (encrypt) ++ bytes_per_frag -= crypt->ops->extra_prefix_len + ++ crypt->ops->extra_postfix_len; ++ ++ /* Number of fragments is the total bytes_per_frag / ++ * payload_per_fragment */ ++ nr_frags = bytes / bytes_per_frag; ++ bytes_last_frag = bytes % bytes_per_frag; ++ if (bytes_last_frag) ++ nr_frags++; ++ else ++ bytes_last_frag = bytes_per_frag; ++ ++ /* When we allocate the TXB we allocate enough space for the reserve ++ * and full fragment bytes (bytes_per_frag doesn't include prefix, ++ * postfix, header, FCS, etc.) */ ++ txb = ieee80211_alloc_txb(nr_frags, frag_size, GFP_ATOMIC); ++ if (unlikely(!txb)) { ++ printk(KERN_WARNING "%s: Could not allocate TXB\n", ++ ieee->dev->name); ++ goto failed; ++ } ++ txb->encrypted = encrypt; ++ txb->payload_size = bytes; ++ ++ for (i = 0; i < nr_frags; i++) { ++ skb_frag = txb->fragments[i]; ++ skb_frag->priority = UP2AC(skb->priority); ++ if (encrypt) ++ skb_reserve(skb_frag, crypt->ops->extra_prefix_len); ++ ++ frag_hdr = (struct ieee80211_hdr_3addr_QOS *)skb_put(skb_frag, hdr_len); ++ memcpy(frag_hdr, &header, hdr_len); ++ ++ /* If this is not the last fragment, then add the MOREFRAGS ++ * bit to the frame control */ ++ if (i != nr_frags - 1) { ++ frag_hdr->frame_ctl = cpu_to_le16( ++ fc | IEEE80211_FCTL_MOREFRAGS); ++ bytes = bytes_per_frag; ++ ++ } else { ++ /* The last fragment takes the remaining length */ ++ bytes = bytes_last_frag; ++ } ++ if(ieee->current_network.QoS_Enable) { ++ // add 1 only indicate to corresponding seq number control 2006/7/12 ++ frag_hdr->seq_ctl = cpu_to_le16(ieee->seq_ctrl[UP2AC(skb->priority)+1]<<4 | i); ++ //printk(KERN_WARNING "skb->priority = %d,", skb->priority); ++ //printk(KERN_WARNING "type:%d: seq = %d\n",UP2AC(skb->priority),ieee->seq_ctrl[UP2AC(skb->priority)+1]); ++ } else { ++ frag_hdr->seq_ctl = cpu_to_le16(ieee->seq_ctrl[0]<<4 | i); ++ } ++ //frag_hdr->seq_ctl = cpu_to_le16(ieee->seq_ctrl<<4 | i); ++ // ++ ++ /* Put a SNAP header on the first fragment */ ++ if (i == 0) { ++ ieee80211_put_snap( ++ skb_put(skb_frag, SNAP_SIZE + sizeof(u16)), ++ ether_type); ++ bytes -= SNAP_SIZE + sizeof(u16); ++ } ++ ++ memcpy(skb_put(skb_frag, bytes), skb->data, bytes); ++ ++ /* Advance the SKB... */ ++ skb_pull(skb, bytes); ++ ++ /* Encryption routine will move the header forward in order ++ * to insert the IV between the header and the payload */ ++ if (encrypt) ++ ieee80211_encrypt_fragment(ieee, skb_frag, hdr_len); ++ if (ieee->config & ++ (CFG_IEEE80211_COMPUTE_FCS | CFG_IEEE80211_RESERVE_FCS)) ++ skb_put(skb_frag, 4); ++ } ++ // Advance sequence number in data frame. ++ //printk(KERN_WARNING "QoS Enalbed? %s\n", ieee->current_network.QoS_Enable?"Y":"N"); ++ if (ieee->current_network.QoS_Enable) { ++ if (ieee->seq_ctrl[UP2AC(skb->priority) + 1] == 0xFFF) ++ ieee->seq_ctrl[UP2AC(skb->priority) + 1] = 0; ++ else ++ ieee->seq_ctrl[UP2AC(skb->priority) + 1]++; ++ } else { ++ if (ieee->seq_ctrl[0] == 0xFFF) ++ ieee->seq_ctrl[0] = 0; ++ else ++ ieee->seq_ctrl[0]++; ++ } ++ //--- ++ }else{ ++ if (unlikely(skb->len < sizeof(struct ieee80211_hdr_3addr))) { ++ printk(KERN_WARNING "%s: skb too small (%d).\n", ++ ieee->dev->name, skb->len); ++ goto success; ++ } ++ ++ txb = ieee80211_alloc_txb(1, skb->len, GFP_ATOMIC); ++ if(!txb){ ++ printk(KERN_WARNING "%s: Could not allocate TXB\n", ++ ieee->dev->name); ++ goto failed; ++ } ++ ++ txb->encrypted = 0; ++ txb->payload_size = skb->len; ++ memcpy(skb_put(txb->fragments[0],skb->len), skb->data, skb->len); ++ } ++ ++ success: ++ spin_unlock_irqrestore(&ieee->lock, flags); ++#ifdef _RTL8187_EXT_PATCH_ ++ // Sometimes, extension mode can reuse skb (by txb->fragments[0]) ++ if( ! ((ieee->iw_mode == ieee->iw_ext_mode) && txb && (txb->fragments[0] == skb)) ) ++#endif ++ dev_kfree_skb_any(skb); ++ if (txb) { ++ if (ieee->softmac_features & IEEE_SOFTMAC_TX_QUEUE){ ++ ieee80211_softmac_xmit(txb, ieee); ++ }else{ ++ if ((*ieee->hard_start_xmit)(txb, dev) == 0) { ++ stats->tx_packets++; ++ stats->tx_bytes += txb->payload_size; ++ return 0; ++ } ++ ieee80211_txb_free(txb); ++ } ++ } ++ ++ return 0; ++ ++ failed: ++ spin_unlock_irqrestore(&ieee->lock, flags); ++ netif_stop_queue(dev); ++ printk("netif_stop_queue in ieee80211_xmit \n"); ++ stats->tx_errors++; ++ return 1; ++ ++} ++ ++ ++ ++#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0)) ++EXPORT_SYMBOL(ieee80211_txb_free); ++#ifdef _RTL8187_EXT_PATCH_ ++EXPORT_SYMBOL(ieee80211_alloc_txb); ++EXPORT_SYMBOL(ieee80211_ext_alloc_txb); ++EXPORT_SYMBOL(ieee80211_ext_reuse_txb); ++ ++EXPORT_SYMBOL(ieee80211_encrypt_fragment); ++#endif // _RTL8187_EXT_PATCH_ ++#else ++EXPORT_SYMBOL_NOVERS(ieee80211_txb_free); ++#ifdef _RTL8187_EXT_PATCH_ ++EXPORT_SYMBOL_NOVERS(ieee80211_alloc_txb); ++EXPORT_SYMBOL_NOVERS(ieee80211_ext_reuse_txb); ++ ++EXPORT_SYMBOL_NOVERS(ieee80211_encrypt_fragment); ++#endif // _RTL8187_EXT_PATCH_ ++#endif ++ +diff -Nur linux-2.6.33/drivers/net/wireless/rtl8187b/ieee80211/ieee80211_wx.c linux-lemote/drivers/net/wireless/rtl8187b/ieee80211/ieee80211_wx.c +--- linux-2.6.33/drivers/net/wireless/rtl8187b/ieee80211/ieee80211_wx.c 1970-01-01 01:00:00.000000000 +0100 ++++ linux-lemote/drivers/net/wireless/rtl8187b/ieee80211/ieee80211_wx.c 2010-03-06 16:43:22.000000000 +0100 +@@ -0,0 +1,926 @@ ++/****************************************************************************** ++ ++ Copyright(c) 2004 Intel Corporation. All rights reserved. ++ ++ Portions of this file are based on the WEP enablement code provided by the ++ Host AP project hostap-drivers v0.1.3 ++ Copyright (c) 2001-2002, SSH Communications Security Corp and Jouni Malinen ++ <jkmaline@cc.hut.fi> ++ Copyright (c) 2002-2003, Jouni Malinen <jkmaline@cc.hut.fi> ++ ++ This program is free software; you can redistribute it and/or modify it ++ under the terms of version 2 of the GNU General Public License as ++ published by the Free Software Foundation. ++ ++ 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. ++ ++ The full GNU General Public License is included in this distribution in the ++ file called LICENSE. ++ ++ Contact Information: ++ James P. Ketrenos <ipw2100-admin@linux.intel.com> ++ Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 ++ ++******************************************************************************/ ++#include <linux/wireless.h> ++#include <linux/version.h> ++#include <linux/kmod.h> ++#include <linux/module.h> ++ ++#include "ieee80211.h" ++static const char *ieee80211_modes[] = { ++ "?", "a", "b", "ab", "g", "ag", "bg", "abg" ++}; ++ ++#define MAX_CUSTOM_LEN 64 ++static inline char *rtl819x_translate_scan(struct ieee80211_device *ieee, ++ char *start, char *stop, ++ struct ieee80211_network *network, ++ struct iw_request_info *info) ++{ ++ char custom[MAX_CUSTOM_LEN]; ++ char *p; ++ struct iw_event iwe; ++ int i, j; ++ u8 max_rate, rate; ++ ++ /* First entry *MUST* be the AP MAC address */ ++ iwe.cmd = SIOCGIWAP; ++ iwe.u.ap_addr.sa_family = ARPHRD_ETHER; ++ memcpy(iwe.u.ap_addr.sa_data, network->bssid, ETH_ALEN); ++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,27) || defined (QMI_26_6)) ++ start = iwe_stream_add_event(info, start, stop, &iwe, IW_EV_ADDR_LEN); ++#else ++ start = iwe_stream_add_event(start, stop, &iwe, IW_EV_ADDR_LEN); ++#endif ++ /* Remaining entries will be displayed in the order we provide them */ ++ ++ /* Add the ESSID */ ++ iwe.cmd = SIOCGIWESSID; ++ iwe.u.data.flags = 1; ++ //YJ,modified,080903,for hidden ap ++ //if (network->flags & NETWORK_EMPTY_ESSID) { ++ if (network->ssid_len == 0) { ++ iwe.u.data.length = sizeof("<hidden>"); ++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,27) || defined (QMI_26_6)) ++ start = iwe_stream_add_point(info, start, stop, &iwe, "<hidden>"); ++#else ++ start = iwe_stream_add_point(start, stop, &iwe, "<hidden>"); ++#endif ++ } else { ++ iwe.u.data.length = min(network->ssid_len, (u8)32); ++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,27) || defined (QMI_26_6)) ++ start = iwe_stream_add_point(info, start, stop, &iwe, network->ssid); ++#else ++ start = iwe_stream_add_point(start, stop, &iwe, network->ssid); ++#endif ++ } ++ ++ /* Add the protocol name */ ++ iwe.cmd = SIOCGIWNAME; ++ snprintf(iwe.u.name, IFNAMSIZ, "IEEE 802.11%s", ieee80211_modes[network->mode]); ++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,27) || defined (QMI_26_6)) ++ start = iwe_stream_add_event(info, start, stop, &iwe, IW_EV_CHAR_LEN); ++#else ++ start = iwe_stream_add_event(start, stop, &iwe, IW_EV_CHAR_LEN); ++#endif ++ /* Add mode */ ++ iwe.cmd = SIOCGIWMODE; ++ if (network->capability & ++ (WLAN_CAPABILITY_BSS | WLAN_CAPABILITY_IBSS)) { ++ if (network->capability & WLAN_CAPABILITY_BSS) ++ iwe.u.mode = IW_MODE_MASTER; ++ else ++ iwe.u.mode = IW_MODE_ADHOC; ++ ++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,27) || defined (QMI_26_6)) ++ start = iwe_stream_add_event(info, start, stop, &iwe, ++ IW_EV_UINT_LEN); ++#else ++ start = iwe_stream_add_event(start, stop, &iwe, ++ IW_EV_UINT_LEN); ++#endif ++ } ++ ++ /* Add frequency/channel */ ++ iwe.cmd = SIOCGIWFREQ; ++/* iwe.u.freq.m = ieee80211_frequency(network->channel, network->mode); ++ iwe.u.freq.e = 3; */ ++ iwe.u.freq.m = network->channel; ++ iwe.u.freq.e = 0; ++ iwe.u.freq.i = 0; ++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,27) || defined (QMI_26_6)) ++ start = iwe_stream_add_event(info, start, stop, &iwe, IW_EV_FREQ_LEN); ++#else ++ start = iwe_stream_add_event(start, stop, &iwe, IW_EV_FREQ_LEN); ++#endif ++ /* Add encryption capability */ ++ iwe.cmd = SIOCGIWENCODE; ++ if (network->capability & WLAN_CAPABILITY_PRIVACY) ++ iwe.u.data.flags = IW_ENCODE_ENABLED | IW_ENCODE_NOKEY; ++ else ++ iwe.u.data.flags = IW_ENCODE_DISABLED; ++ iwe.u.data.length = 0; ++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,27) || defined (QMI_26_6)) ++ start = iwe_stream_add_point(info, start, stop, &iwe, network->ssid); ++#else ++ start = iwe_stream_add_point(start, stop, &iwe, network->ssid); ++#endif ++ /* Add basic and extended rates */ ++ max_rate = 0; ++ p = custom; ++ p += snprintf(p, MAX_CUSTOM_LEN - (p - custom), " Rates (Mb/s): "); ++ for (i = 0, j = 0; i < network->rates_len; ) { ++ if (j < network->rates_ex_len && ++ ((network->rates_ex[j] & 0x7F) < ++ (network->rates[i] & 0x7F))) ++ rate = network->rates_ex[j++] & 0x7F; ++ else ++ rate = network->rates[i++] & 0x7F; ++ if (rate > max_rate) ++ max_rate = rate; ++ p += snprintf(p, MAX_CUSTOM_LEN - (p - custom), ++ "%d%s ", rate >> 1, (rate & 1) ? ".5" : ""); ++ } ++ for (; j < network->rates_ex_len; j++) { ++ rate = network->rates_ex[j] & 0x7F; ++ p += snprintf(p, MAX_CUSTOM_LEN - (p - custom), ++ "%d%s ", rate >> 1, (rate & 1) ? ".5" : ""); ++ if (rate > max_rate) ++ max_rate = rate; ++ } ++ ++ iwe.cmd = SIOCGIWRATE; ++ iwe.u.bitrate.fixed = iwe.u.bitrate.disabled = 0; ++ iwe.u.bitrate.value = max_rate * 500000; ++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,27) || defined (QMI_26_6)) ++ start = iwe_stream_add_event(info, start, stop, &iwe,IW_EV_PARAM_LEN); ++#else ++ start = iwe_stream_add_event(start, stop, &iwe,IW_EV_PARAM_LEN); ++#endif ++ iwe.cmd = IWEVCUSTOM; ++ iwe.u.data.length = p - custom; ++ if (iwe.u.data.length) ++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,27) || defined (QMI_26_6)) ++ start = iwe_stream_add_point(info, start, stop, &iwe, custom); ++#else ++ start = iwe_stream_add_point(start, stop, &iwe, custom); ++#endif ++ /* Add quality statistics */ ++ /* TODO: Fix these values... */ ++ iwe.cmd = IWEVQUAL; ++ iwe.u.qual.qual = network->stats.signalstrength;//network->stats.signal; ++ iwe.u.qual.level = network->stats.signal;//network->stats.rssi; ++ iwe.u.qual.noise = network->stats.noise; ++#if 0 ++ iwe.u.qual.updated = network->stats.mask & IEEE80211_STATMASK_WEMASK; ++ if (!(network->stats.mask & IEEE80211_STATMASK_RSSI)) ++ iwe.u.qual.updated |= IW_QUAL_LEVEL_INVALID; ++ if (!(network->stats.mask & IEEE80211_STATMASK_NOISE)) ++ iwe.u.qual.updated |= IW_QUAL_NOISE_INVALID; ++ if (!(network->stats.mask & IEEE80211_STATMASK_SIGNAL)) ++ iwe.u.qual.updated |= IW_QUAL_QUAL_INVALID; ++#endif ++ ++ iwe.u.qual.updated = 0x7;//network->stats.mask & IEEE80211_STATMASK_WEMASK; ++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,27) || defined (QMI_26_6)) ++ start = iwe_stream_add_event(info, start, stop, &iwe, IW_EV_QUAL_LEN); ++#else ++ start = iwe_stream_add_event(start, stop, &iwe, IW_EV_QUAL_LEN); ++#endif ++ iwe.cmd = IWEVCUSTOM; ++ p = custom; ++ ++ iwe.u.data.length = p - custom; ++ if (iwe.u.data.length) ++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,27) || defined (QMI_26_6)) ++ start = iwe_stream_add_point(info, start, stop, &iwe, custom); ++#else ++ start = iwe_stream_add_point(start, stop, &iwe, custom); ++#endif ++#if 0 ++ if (ieee->wpa_enabled && network->wpa_ie_len){ ++ char buf[MAX_WPA_IE_LEN * 2 + 30]; ++ // printk("WPA IE\n"); ++ u8 *p = buf; ++ p += sprintf(p, "wpa_ie="); ++ for (i = 0; i < network->wpa_ie_len; i++) { ++ p += sprintf(p, "%02x", network->wpa_ie[i]); ++ } ++ ++ memset(&iwe, 0, sizeof(iwe)); ++ iwe.cmd = IWEVCUSTOM; ++ iwe.u.data.length = strlen(buf); ++ start = iwe_stream_add_point(start, stop, &iwe, buf); ++ } ++ ++ if (ieee->wpa_enabled && network->rsn_ie_len){ ++ char buf[MAX_WPA_IE_LEN * 2 + 30]; ++ ++ u8 *p = buf; ++ p += sprintf(p, "rsn_ie="); ++ for (i = 0; i < network->rsn_ie_len; i++) { ++ p += sprintf(p, "%02x", network->rsn_ie[i]); ++ } ++ ++ ++#else ++ memset(&iwe, 0, sizeof(iwe)); ++ if (network->wpa_ie_len) { ++ //printk("wpa_ie_len:%d\n", network->wpa_ie_len); ++ char buf[MAX_WPA_IE_LEN]; ++ memcpy(buf, network->wpa_ie, network->wpa_ie_len); ++ iwe.cmd = IWEVGENIE; ++ iwe.u.data.length = network->wpa_ie_len; ++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,27) || defined (QMI_26_6)) ++ start = iwe_stream_add_point(info, start, stop, &iwe, buf); ++#else ++ start = iwe_stream_add_point(start, stop, &iwe, buf); ++#endif ++ } ++ ++ memset(&iwe, 0, sizeof(iwe)); ++ if (network->rsn_ie_len) { ++ //printk("=====>rsn_ie_len:\n", network->rsn_ie_len); ++ #if 0 ++ { ++ int i; ++ for (i=0; i<network->rsn_ie_len; i++); ++ printk("%2x ", network->rsn_ie[i]); ++ printk("\n"); ++ } ++ #endif ++ char buf[MAX_WPA_IE_LEN]; ++ memcpy(buf, network->rsn_ie, network->rsn_ie_len); ++ iwe.cmd = IWEVGENIE; ++ iwe.u.data.length = network->rsn_ie_len; ++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,27) || defined (QMI_26_6)) ++ start = iwe_stream_add_point(info, start, stop, &iwe, buf); ++#else ++ start = iwe_stream_add_point(start, stop, &iwe, buf); ++#endif ++ } ++ ++#endif ++ ++ /* Add EXTRA: Age to display seconds since last beacon/probe response ++ * for given network. */ ++ iwe.cmd = IWEVCUSTOM; ++ p = custom; ++ p += snprintf(p, MAX_CUSTOM_LEN - (p - custom), ++ " Last beacon: %lums ago", (jiffies - network->last_scanned) / (HZ / 100)); ++ iwe.u.data.length = p - custom; ++ if (iwe.u.data.length) ++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,27) || defined (QMI_26_6)) ++ start = iwe_stream_add_point(info, start, stop, &iwe, custom); ++#else ++ start = iwe_stream_add_point(start, stop, &iwe, custom); ++#endif ++ ++ return start; ++} ++ ++int ieee80211_wx_get_scan(struct ieee80211_device *ieee, ++ struct iw_request_info *info, ++ union iwreq_data *wrqu, char *extra) ++{ ++ struct ieee80211_network *network; ++ unsigned long flags; ++ int err = 0; ++ char *ev = extra; ++ char *stop = ev + wrqu->data.length;//IW_SCAN_MAX_DATA; ++ //char *stop = ev + IW_SCAN_MAX_DATA; ++ int i = 0; ++ ++ IEEE80211_DEBUG_WX("Getting scan\n"); ++ down(&ieee->wx_sem); ++ spin_lock_irqsave(&ieee->lock, flags); ++ ++ if(!ieee->bHwRadioOff) ++ { ++ list_for_each_entry(network, &ieee->network_list, list) { ++ i++; ++ ++ if((stop-ev)<200) ++ { ++ err = -E2BIG; ++ break; ++ } ++ ++ if (ieee->scan_age == 0 || ++ time_after(network->last_scanned + ieee->scan_age, jiffies)) ++ { ++ ev = rtl819x_translate_scan(ieee, ev, stop, network, info); ++ } ++ else ++ IEEE80211_DEBUG_SCAN( ++ "Not showing network '%s (" ++ MAC_FMT ")' due to age (%lums).\n", ++ escape_essid(network->ssid, ++ network->ssid_len), ++ MAC_ARG(network->bssid), ++ (jiffies - network->last_scanned) / (HZ / 100)); ++ } ++ } ++ spin_unlock_irqrestore(&ieee->lock, flags); ++ up(&ieee->wx_sem); ++ wrqu->data.length = ev - extra; ++ wrqu->data.flags = 0; ++ ++ IEEE80211_DEBUG_WX("exit: %d networks returned.\n", i); ++ ++ return err; ++} ++ ++int ieee80211_wx_set_encode(struct ieee80211_device *ieee, ++ struct iw_request_info *info, ++ union iwreq_data *wrqu, char *keybuf) ++{ ++ struct iw_point *erq = &(wrqu->encoding); ++ struct net_device *dev = ieee->dev; ++ struct ieee80211_security sec = { ++ .flags = 0 ++ }; ++ int i, key, key_provided, len; ++ struct ieee80211_crypt_data **crypt; ++ ++ IEEE80211_DEBUG_WX("SET_ENCODE\n"); ++ ++ key = erq->flags & IW_ENCODE_INDEX; ++ if (key) { ++ if (key > WEP_KEYS) ++ return -EINVAL; ++ key--; ++ key_provided = 1; ++ } else { ++ key_provided = 0; ++ key = ieee->tx_keyidx; ++ } ++ ++ IEEE80211_DEBUG_WX("Key: %d [%s]\n", key, key_provided ? ++ "provided" : "default"); ++#ifdef _RTL8187_EXT_PATCH_ ++#if 0 ++{ ++ int j; ++ for(j=0; j<MAX_MP; j++){ ++ crypt = &ieee->cryptlist[j]->crypt[key]; ++#else ++ crypt = &ieee->cryptlist[0]->crypt[key]; ++#endif ++#else ++ crypt = &ieee->crypt[key]; ++#endif ++ if (erq->flags & IW_ENCODE_DISABLED) { ++ if (key_provided && *crypt) { ++ IEEE80211_DEBUG_WX("Disabling encryption on key %d.\n", ++ key); ++ ieee80211_crypt_delayed_deinit(ieee, crypt); ++ } else ++ IEEE80211_DEBUG_WX("Disabling encryption.\n"); ++ ++ /* Check all the keys to see if any are still configured, ++ * and if no key index was provided, de-init them all */ ++ for (i = 0; i < WEP_KEYS; i++) { ++#ifdef _RTL8187_EXT_PATCH_ ++ ++ if (ieee->cryptlist[0]->crypt[i] != NULL){ ++#else ++ ++ if (ieee->crypt[i] != NULL) { ++#endif ++ if (key_provided) ++ break; ++ ieee80211_crypt_delayed_deinit( ++#ifdef _RTL8187_EXT_PATCH_ ++ ieee, &ieee->cryptlist[0]->crypt[i]); ++#else ++ ieee, &ieee->crypt[i]); ++#endif ++ } ++ } ++ ++ if (i == WEP_KEYS) { ++ sec.enabled = 0; ++ sec.level = SEC_LEVEL_0; ++ sec.flags |= SEC_ENABLED | SEC_LEVEL; ++ } ++ ++ goto done; ++ } ++ ++ ++ ++ sec.enabled = 1; ++ sec.flags |= SEC_ENABLED; ++ ++ if (*crypt != NULL && (*crypt)->ops != NULL && ++ strcmp((*crypt)->ops->name, "WEP") != 0) { ++ /* changing to use WEP; deinit previously used algorithm ++ * on this key */ ++ ieee80211_crypt_delayed_deinit(ieee, crypt); ++ } ++ ++ if (*crypt == NULL) { ++ struct ieee80211_crypt_data *new_crypt; ++ ++ /* take WEP into use */ ++ new_crypt = kmalloc(sizeof(struct ieee80211_crypt_data), ++ GFP_KERNEL); ++ if (new_crypt == NULL) ++ return -ENOMEM; ++ memset(new_crypt, 0, sizeof(struct ieee80211_crypt_data)); ++ new_crypt->ops = ieee80211_get_crypto_ops("WEP"); ++ if (!new_crypt->ops) { ++ request_module("ieee80211_crypt_wep"); ++ new_crypt->ops = ieee80211_get_crypto_ops("WEP"); ++ } ++#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0) ++ if (new_crypt->ops && try_module_get(new_crypt->ops->owner)) ++#else ++ if (new_crypt->ops && try_inc_mod_count(new_crypt->ops->owner)) ++#endif ++ new_crypt->priv = new_crypt->ops->init(key); ++ ++ if (!new_crypt->ops || !new_crypt->priv) { ++ kfree(new_crypt); ++ new_crypt = NULL; ++ ++ printk(KERN_WARNING "%s: could not initialize WEP: " ++ "load module ieee80211_crypt_wep\n", ++ dev->name); ++ return -EOPNOTSUPP; ++ } ++ *crypt = new_crypt; ++ } ++ ++ /* If a new key was provided, set it up */ ++ if (erq->length > 0) { ++ len = erq->length <= 5 ? 5 : 13; ++ memcpy(sec.keys[key], keybuf, erq->length); ++ if (len > erq->length) ++ memset(sec.keys[key] + erq->length, 0, ++ len - erq->length); ++ IEEE80211_DEBUG_WX("Setting key %d to '%s' (%d:%d bytes)\n", ++ key, escape_essid(sec.keys[key], len), ++ erq->length, len); ++ sec.key_sizes[key] = len; ++ (*crypt)->ops->set_key(sec.keys[key], len, NULL, ++ (*crypt)->priv); ++ sec.flags |= (1 << key); ++ /* This ensures a key will be activated if no key is ++ * explicitely set */ ++ if (key == sec.active_key) ++ sec.flags |= SEC_ACTIVE_KEY; ++ ++ ieee->tx_keyidx = key; //we need it to support multi_key setting. added by wb 2008_2_22 ++ } else { ++ len = (*crypt)->ops->get_key(sec.keys[key], WEP_KEY_LEN, ++ NULL, (*crypt)->priv); ++ if (len == 0) { ++ /* Set a default key of all 0 */ ++ IEEE80211_DEBUG_WX("Setting key %d to all zero.\n", ++ key); ++ memset(sec.keys[key], 0, 13); ++ (*crypt)->ops->set_key(sec.keys[key], 13, NULL, ++ (*crypt)->priv); ++ sec.key_sizes[key] = 13; ++ sec.flags |= (1 << key); ++ } ++ ++ /* No key data - just set the default TX key index */ ++ if (key_provided) { ++ IEEE80211_DEBUG_WX( ++ "Setting key %d to default Tx key.\n", key); ++ ieee->tx_keyidx = key; ++ sec.active_key = key; ++ sec.flags |= SEC_ACTIVE_KEY; ++ } ++ } ++#ifdef _RTL8187_EXT_PATCH_ ++#if 0 ++} ++} ++#endif ++#endif ++ done: ++ ieee->open_wep = !(erq->flags & IW_ENCODE_RESTRICTED); ++ sec.auth_mode = ieee->open_wep ? WLAN_AUTH_OPEN : WLAN_AUTH_SHARED_KEY; ++ sec.flags |= SEC_AUTH_MODE; ++ IEEE80211_DEBUG_WX("Auth: %s\n", sec.auth_mode == WLAN_AUTH_OPEN ? ++ "OPEN" : "SHARED KEY"); ++ ++ /* For now we just support WEP, so only set that security level... ++ * TODO: When WPA is added this is one place that needs to change */ ++ sec.flags |= SEC_LEVEL; ++ sec.level = SEC_LEVEL_1; /* 40 and 104 bit WEP */ ++ ++ if (ieee->set_security) ++ ieee->set_security(dev, &sec); ++ ++ /* Do not reset port if card is in Managed mode since resetting will ++ * generate new IEEE 802.11 authentication which may end up in looping ++ * with IEEE 802.1X. If your hardware requires a reset after WEP ++ * configuration (for example... Prism2), implement the reset_port in ++ * the callbacks structures used to initialize the 802.11 stack. */ ++ if (ieee->reset_on_keychange && ++ ieee->iw_mode != IW_MODE_INFRA && ++ ieee->reset_port && ieee->reset_port(dev)) { ++ printk(KERN_DEBUG "%s: reset_port failed\n", dev->name); ++ return -EINVAL; ++ } ++ return 0; ++} ++ ++int ieee80211_wx_get_encode(struct ieee80211_device *ieee, ++ struct iw_request_info *info, ++ union iwreq_data *wrqu, char *keybuf) ++{ ++ struct iw_point *erq = &(wrqu->encoding); ++ int len, key; ++ struct ieee80211_crypt_data *crypt; ++ ++ IEEE80211_DEBUG_WX("GET_ENCODE\n"); ++ ++ if(ieee->iw_mode == IW_MODE_MONITOR) ++ return -1; ++ ++ key = erq->flags & IW_ENCODE_INDEX; ++ if (key) { ++ if (key > WEP_KEYS) ++ return -EINVAL; ++ key--; ++ } else ++ key = ieee->tx_keyidx; ++#ifdef _RTL8187_EXT_PATCH_ ++ crypt = ieee->cryptlist[0]->crypt[key]; ++#else ++ crypt = ieee->crypt[key]; ++#endif ++ erq->flags = key + 1; ++ ++ if (crypt == NULL || crypt->ops == NULL) { ++ erq->length = 0; ++ erq->flags |= IW_ENCODE_DISABLED; ++ return 0; ++ } ++ ++ if (strcmp(crypt->ops->name, "WEP") != 0) { ++ /* only WEP is supported with wireless extensions, so just ++ * report that encryption is used */ ++ erq->length = 0; ++ erq->flags |= IW_ENCODE_ENABLED; ++ return 0; ++ } ++ ++ len = crypt->ops->get_key(keybuf, WEP_KEY_LEN, NULL, crypt->priv); ++ erq->length = (len >= 0 ? len : 0); ++ ++ erq->flags |= IW_ENCODE_ENABLED; ++ ++ if (ieee->open_wep) ++ erq->flags |= IW_ENCODE_OPEN; ++ else ++ erq->flags |= IW_ENCODE_RESTRICTED; ++ ++ return 0; ++} ++ ++int ieee80211_wx_set_encode_ext(struct ieee80211_device *ieee, ++ struct iw_request_info *info, ++ union iwreq_data *wrqu, char *extra) ++{ ++ struct net_device *dev = ieee->dev; ++ struct iw_point *encoding = &wrqu->encoding; ++ struct iw_encode_ext *ext = (struct iw_encode_ext *)extra; ++ int i, idx, ret = 0; ++ int group_key = 0; ++ const char *alg, *module; ++ struct ieee80211_crypto_ops *ops; ++ struct ieee80211_crypt_data **crypt; ++ ++ struct ieee80211_security sec = { ++ .flags = 0, ++ }; ++ //printk("======>encoding flag:%x,ext flag:%x, ext alg:%d\n", encoding->flags,ext->ext_flags, ext->alg); ++ idx = encoding->flags & IW_ENCODE_INDEX; ++ if (idx) { ++ if (idx < 1 || idx > WEP_KEYS) ++ return -EINVAL; ++ idx--; ++ } else ++ idx = ieee->tx_keyidx; ++ ++ if (ext->ext_flags & IW_ENCODE_EXT_GROUP_KEY) { ++#ifdef _RTL8187_EXT_PATCH_ ++ crypt = &ieee->cryptlist[0]->crypt[idx]; ++#else ++ crypt = &ieee->crypt[idx]; ++#endif ++ group_key = 1; ++ } else { ++ /* some Cisco APs use idx>0 for unicast in dynamic WEP */ ++ //printk("not group key, flags:%x, ext->alg:%d\n", ext->ext_flags, ext->alg); ++ if (idx != 0 && ext->alg != IW_ENCODE_ALG_WEP) ++ return -EINVAL; ++ if (ieee->iw_mode == IW_MODE_INFRA) ++#ifdef _RTL8187_EXT_PATCH_ ++ crypt = &ieee->cryptlist[0]->crypt[idx]; ++#else ++ crypt = &ieee->crypt[idx]; ++#endif ++ else ++ return -EINVAL; ++ } ++ ++ sec.flags |= SEC_ENABLED;// | SEC_ENCRYPT; ++ if ((encoding->flags & IW_ENCODE_DISABLED) || ++ ext->alg == IW_ENCODE_ALG_NONE) { ++ if (*crypt) ++ ieee80211_crypt_delayed_deinit(ieee, crypt); ++ ++ for (i = 0; i < WEP_KEYS; i++) ++#ifdef _RTL8187_EXT_PATCH_ ++ if (ieee->cryptlist[0]->crypt[i] != NULL) ++#else ++ if (ieee->crypt[i] != NULL) ++#endif ++ break; ++ ++ if (i == WEP_KEYS) { ++ sec.enabled = 0; ++ // sec.encrypt = 0; ++ sec.level = SEC_LEVEL_0; ++ sec.flags |= SEC_LEVEL; ++ } ++ //printk("disabled: flag:%x\n", encoding->flags); ++ goto done; ++ } ++ ++ sec.enabled = 1; ++ // sec.encrypt = 1; ++#if 0 ++ if (group_key ? !ieee->host_mc_decrypt : ++ !(ieee->host_encrypt || ieee->host_decrypt || ++ ieee->host_encrypt_msdu)) ++ goto skip_host_crypt; ++#endif ++ switch (ext->alg) { ++ case IW_ENCODE_ALG_WEP: ++ alg = "WEP"; ++ module = "ieee80211_crypt_wep"; ++ break; ++ case IW_ENCODE_ALG_TKIP: ++ alg = "TKIP"; ++ module = "ieee80211_crypt_tkip"; ++ break; ++ case IW_ENCODE_ALG_CCMP: ++ alg = "CCMP"; ++ module = "ieee80211_crypt_ccmp"; ++ break; ++ default: ++ IEEE80211_DEBUG_WX("%s: unknown crypto alg %d\n", ++ dev->name, ext->alg); ++ ret = -EINVAL; ++ goto done; ++ } ++ printk("alg name:%s\n",alg); ++ ++ ops = ieee80211_get_crypto_ops(alg); ++ if (ops == NULL) { ++ request_module(module); ++ ops = ieee80211_get_crypto_ops(alg); ++ } ++ if (ops == NULL) { ++ IEEE80211_DEBUG_WX("%s: unknown crypto alg %d\n", ++ dev->name, ext->alg); ++ printk("========>unknown crypto alg %d\n", ext->alg); ++ ret = -EINVAL; ++ goto done; ++ } ++ ++ if (*crypt == NULL || (*crypt)->ops != ops) { ++ struct ieee80211_crypt_data *new_crypt; ++ ++ ieee80211_crypt_delayed_deinit(ieee, crypt); ++ ++ new_crypt = kzalloc(sizeof(*new_crypt), GFP_KERNEL); ++ if (new_crypt == NULL) { ++ ret = -ENOMEM; ++ goto done; ++ } ++ new_crypt->ops = ops; ++ if (new_crypt->ops && try_module_get(new_crypt->ops->owner)) ++ new_crypt->priv = new_crypt->ops->init(idx); ++ if (new_crypt->priv == NULL) { ++ kfree(new_crypt); ++ ret = -EINVAL; ++ goto done; ++ } ++ *crypt = new_crypt; ++ ++ } ++ //I need to deinit other crypt here in mesh mode instead deinit them while use them to tx&rx. ++#ifdef _RTL8187_EXT_PATCH_ ++ if (ieee->iw_mode == ieee->iw_ext_mode) ++ { ++ int j; ++ for (j=1; j<MAX_MP; j++) ++ { ++ struct ieee80211_crypt_data ** crypttmp = &ieee->cryptlist[j]->crypt[idx]; ++ if (*crypttmp == NULL) ++ break; ++ if (*crypttmp && (*crypttmp)->ops != ops) ++ ieee80211_crypt_delayed_deinit(ieee, crypttmp); ++ } ++ } ++#endif ++ if (ext->key_len > 0 && (*crypt)->ops->set_key && ++ (*crypt)->ops->set_key(ext->key, ext->key_len, ext->rx_seq, ++ (*crypt)->priv) < 0) { ++ IEEE80211_DEBUG_WX("%s: key setting failed\n", dev->name); ++ printk("key setting failed\n"); ++ ret = -EINVAL; ++ goto done; ++ } ++#if 1 ++// skip_host_crypt: ++ //printk("skip_host_crypt:ext_flags:%x\n", ext->ext_flags); ++ if (ext->ext_flags & IW_ENCODE_EXT_SET_TX_KEY) { ++ ieee->tx_keyidx = idx; ++ sec.active_key = idx; ++ sec.flags |= SEC_ACTIVE_KEY; ++ } ++ ++ if (ext->alg != IW_ENCODE_ALG_NONE) { ++ memcpy(sec.keys[idx], ext->key, ext->key_len); ++ sec.key_sizes[idx] = ext->key_len; ++ sec.flags |= (1 << idx); ++ if (ext->alg == IW_ENCODE_ALG_WEP) { ++ // sec.encode_alg[idx] = SEC_ALG_WEP; ++ sec.flags |= SEC_LEVEL; ++ sec.level = SEC_LEVEL_1; ++ } else if (ext->alg == IW_ENCODE_ALG_TKIP) { ++ // sec.encode_alg[idx] = SEC_ALG_TKIP; ++ sec.flags |= SEC_LEVEL; ++ sec.level = SEC_LEVEL_2; ++ } else if (ext->alg == IW_ENCODE_ALG_CCMP) { ++ // sec.encode_alg[idx] = SEC_ALG_CCMP; ++ sec.flags |= SEC_LEVEL; ++ sec.level = SEC_LEVEL_3; ++ } ++ /* Don't set sec level for group keys. */ ++ if (group_key) ++ sec.flags &= ~SEC_LEVEL; ++ } ++#endif ++done: ++ if (ieee->set_security) ++ ieee->set_security(ieee->dev, &sec); ++ ++ if (ieee->reset_on_keychange && ++ ieee->iw_mode != IW_MODE_INFRA && ++ ieee->reset_port && ieee->reset_port(dev)) { ++ IEEE80211_DEBUG_WX("%s: reset_port failed\n", dev->name); ++ return -EINVAL; ++ } ++ ++ return ret; ++} ++int ieee80211_wx_set_mlme(struct ieee80211_device *ieee, ++ struct iw_request_info *info, ++ union iwreq_data *wrqu, char *extra) ++{ ++ struct iw_mlme *mlme = (struct iw_mlme *) extra; ++// printk("\ndkgadfslkdjgalskdf===============>%s(), cmd:%x\n", __FUNCTION__, mlme->cmd); ++#if 1 ++ switch (mlme->cmd) { ++ case IW_MLME_DEAUTH: ++ case IW_MLME_DISASSOC: ++ // printk("disassoc now\n"); ++ ieee80211_disassociate(ieee); ++ break; ++ default: ++ return -EOPNOTSUPP; ++ } ++#endif ++ return 0; ++} ++ ++int ieee80211_wx_set_auth(struct ieee80211_device *ieee, ++ struct iw_request_info *info, ++ struct iw_param *data, char *extra) ++{ ++/* ++ struct ieee80211_security sec = { ++ .flags = SEC_AUTH_MODE, ++ } ++*/ ++ //printk("set auth:flag:%x, data value:%x\n", data->flags, data->value); ++ switch (data->flags & IW_AUTH_INDEX) { ++ case IW_AUTH_WPA_VERSION: ++ /*need to support wpa2 here*/ ++ //printk("wpa version:%x\n", data->value); ++ break; ++ case IW_AUTH_CIPHER_PAIRWISE: ++ case IW_AUTH_CIPHER_GROUP: ++ case IW_AUTH_KEY_MGMT: ++ /* ++ * * Host AP driver does not use these parameters and allows ++ * * wpa_supplicant to control them internally. ++ * */ ++ break; ++ case IW_AUTH_TKIP_COUNTERMEASURES: ++ ieee->tkip_countermeasures = data->value; ++ break; ++ case IW_AUTH_DROP_UNENCRYPTED: ++ ieee->drop_unencrypted = data->value; ++ break; ++ ++ case IW_AUTH_80211_AUTH_ALG: ++ ieee->open_wep = (data->value&IW_AUTH_ALG_OPEN_SYSTEM)?1:0; ++ //printk("open_wep:%d\n", ieee->open_wep); ++ break; ++ ++#if 1 ++ case IW_AUTH_WPA_ENABLED: ++ ieee->wpa_enabled = (data->value)?1:0; ++ //printk("enalbe wpa:%d\n", ieee->wpa_enabled); ++ break; ++ ++#endif ++ case IW_AUTH_RX_UNENCRYPTED_EAPOL: ++ ieee->ieee802_1x = data->value; ++ break; ++ case IW_AUTH_PRIVACY_INVOKED: ++ ieee->privacy_invoked = data->value; ++ break; ++ default: ++ return -EOPNOTSUPP; ++ } ++ return 0; ++} ++ ++#if 1 ++int ieee80211_wx_set_gen_ie(struct ieee80211_device *ieee, u8 *ie, size_t len) ++{ ++#if 0 ++ printk("====>%s()\n", __FUNCTION__); ++ { ++ int i; ++ for (i=0; i<len; i++) ++ printk("%2x ", ie[i]&0xff); ++ printk("\n"); ++ } ++#endif ++ u8 *buf = NULL; ++ ++ if (len>MAX_WPA_IE_LEN || (len && ie == NULL)) ++ { ++ // printk("return error out, len:%d\n", len); ++ return -EINVAL; ++ } ++ if (len) ++ { ++ ++ if (len != ie[1]+2) printk("len:%d, ie:%d\n", (int)len, ie[1]); ++ buf = kmalloc(len, GFP_KERNEL); ++ if (buf == NULL) ++ return -ENOMEM; ++ memcpy(buf, ie, len); ++ kfree(ieee->wpa_ie); ++ ieee->wpa_ie = buf; ++ ieee->wpa_ie_len = len; ++ } ++ else{ ++ if (ieee->wpa_ie) ++ kfree(ieee->wpa_ie); ++ ieee->wpa_ie = NULL; ++ ieee->wpa_ie_len = 0; ++ } ++// printk("<=====out %s()\n", __FUNCTION__); ++ ++ return 0; ++ ++} ++#endif ++ ++EXPORT_SYMBOL(ieee80211_wx_set_gen_ie); ++EXPORT_SYMBOL(ieee80211_wx_set_mlme); ++EXPORT_SYMBOL(ieee80211_wx_set_auth); ++EXPORT_SYMBOL(ieee80211_wx_set_encode_ext); ++EXPORT_SYMBOL(ieee80211_wx_get_scan); ++EXPORT_SYMBOL(ieee80211_wx_set_encode); ++EXPORT_SYMBOL(ieee80211_wx_get_encode); ++#if 0 ++EXPORT_SYMBOL_NOVERS(ieee80211_wx_get_scan); ++EXPORT_SYMBOL_NOVERS(ieee80211_wx_set_encode); ++EXPORT_SYMBOL_NOVERS(ieee80211_wx_get_encode); ++#endif +diff -Nur linux-2.6.33/drivers/net/wireless/rtl8187b/ieee80211/internal.h linux-lemote/drivers/net/wireless/rtl8187b/ieee80211/internal.h +--- linux-2.6.33/drivers/net/wireless/rtl8187b/ieee80211/internal.h 1970-01-01 01:00:00.000000000 +0100 ++++ linux-lemote/drivers/net/wireless/rtl8187b/ieee80211/internal.h 2010-03-06 16:43:22.000000000 +0100 +@@ -0,0 +1,115 @@ ++/* ++ * Cryptographic API. ++ * ++ * Copyright (c) 2002 James Morris <jmorris@intercode.com.au> ++ * ++ * This program is free software; you can redistribute it and/or modify it ++ * under the terms of the GNU General Public License as published by the Free ++ * Software Foundation; either version 2 of the License, or (at your option) ++ * any later version. ++ * ++ */ ++#ifndef _CRYPTO_INTERNAL_H ++#define _CRYPTO_INTERNAL_H ++ ++ ++//#include <linux/crypto.h> ++#include "rtl_crypto.h" ++#include <linux/mm.h> ++#include <linux/highmem.h> ++#include <linux/init.h> ++#include <asm/hardirq.h> ++#include <asm/softirq.h> ++#include <asm/kmap_types.h> ++ ++#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,4,20)) ++#define list_for_each_entry(pos, head, member) \ ++ for (pos = list_entry((head)->next, typeof(*pos), member), \ ++ prefetch(pos->member.next); \ ++ &pos->member != (head); \ ++ pos = list_entry(pos->member.next, typeof(*pos), member), \ ++ prefetch(pos->member.next)) ++ ++static inline void cond_resched(void) ++{ ++ if (need_resched()) { ++ set_current_state(TASK_RUNNING); ++ schedule(); ++ } ++} ++#endif ++ ++extern enum km_type crypto_km_types[]; ++ ++static inline enum km_type crypto_kmap_type(int out) ++{ ++ return crypto_km_types[(in_softirq() ? 2 : 0) + out]; ++} ++ ++static inline void *crypto_kmap(struct page *page, int out) ++{ ++ return kmap_atomic(page, crypto_kmap_type(out)); ++} ++ ++static inline void crypto_kunmap(void *vaddr, int out) ++{ ++ kunmap_atomic(vaddr, crypto_kmap_type(out)); ++} ++ ++static inline void crypto_yield(struct crypto_tfm *tfm) ++{ ++ if (!in_softirq()) ++ cond_resched(); ++} ++ ++static inline void *crypto_tfm_ctx(struct crypto_tfm *tfm) ++{ ++ return (void *)&tfm[1]; ++} ++ ++struct crypto_alg *crypto_alg_lookup(const char *name); ++ ++#ifdef CONFIG_KMOD ++void crypto_alg_autoload(const char *name); ++struct crypto_alg *crypto_alg_mod_lookup(const char *name); ++#else ++static inline struct crypto_alg *crypto_alg_mod_lookup(const char *name) ++{ ++ return crypto_alg_lookup(name); ++} ++#endif ++ ++#ifdef CONFIG_CRYPTO_HMAC ++int crypto_alloc_hmac_block(struct crypto_tfm *tfm); ++void crypto_free_hmac_block(struct crypto_tfm *tfm); ++#else ++static inline int crypto_alloc_hmac_block(struct crypto_tfm *tfm) ++{ ++ return 0; ++} ++ ++static inline void crypto_free_hmac_block(struct crypto_tfm *tfm) ++{ } ++#endif ++ ++#ifdef CONFIG_PROC_FS ++void __init crypto_init_proc(void); ++#else ++static inline void crypto_init_proc(void) ++{ } ++#endif ++ ++int crypto_init_digest_flags(struct crypto_tfm *tfm, u32 flags); ++int crypto_init_cipher_flags(struct crypto_tfm *tfm, u32 flags); ++int crypto_init_compress_flags(struct crypto_tfm *tfm, u32 flags); ++ ++int crypto_init_digest_ops(struct crypto_tfm *tfm); ++int crypto_init_cipher_ops(struct crypto_tfm *tfm); ++int crypto_init_compress_ops(struct crypto_tfm *tfm); ++ ++void crypto_exit_digest_ops(struct crypto_tfm *tfm); ++void crypto_exit_cipher_ops(struct crypto_tfm *tfm); ++void crypto_exit_compress_ops(struct crypto_tfm *tfm); ++ ++#endif /* _CRYPTO_INTERNAL_H */ ++ +diff -Nur linux-2.6.33/drivers/net/wireless/rtl8187b/ieee80211/kmap_types.h linux-lemote/drivers/net/wireless/rtl8187b/ieee80211/kmap_types.h +--- linux-2.6.33/drivers/net/wireless/rtl8187b/ieee80211/kmap_types.h 1970-01-01 01:00:00.000000000 +0100 ++++ linux-lemote/drivers/net/wireless/rtl8187b/ieee80211/kmap_types.h 2010-03-06 16:43:22.000000000 +0100 +@@ -0,0 +1,20 @@ ++#ifndef __KMAP_TYPES_H ++ ++#define __KMAP_TYPES_H ++ ++ ++enum km_type { ++ KM_BOUNCE_READ, ++ KM_SKB_SUNRPC_DATA, ++ KM_SKB_DATA_SOFTIRQ, ++ KM_USER0, ++ KM_USER1, ++ KM_BH_IRQ, ++ KM_SOFTIRQ0, ++ KM_SOFTIRQ1, ++ KM_TYPE_NR ++}; ++ ++#define _ASM_KMAP_TYPES_H ++ ++#endif +diff -Nur linux-2.6.33/drivers/net/wireless/rtl8187b/ieee80211/readme linux-lemote/drivers/net/wireless/rtl8187b/ieee80211/readme +--- linux-2.6.33/drivers/net/wireless/rtl8187b/ieee80211/readme 1970-01-01 01:00:00.000000000 +0100 ++++ linux-lemote/drivers/net/wireless/rtl8187b/ieee80211/readme 2010-03-06 16:43:22.000000000 +0100 +@@ -0,0 +1,162 @@ ++What this layer should do ++ ++- It mantain the old mechanism as alternative, so the ++ ipw2100 driver works with really few changes. ++- Encapsulate / Decapsulate ieee80211 packet ++- Handle fragmentation ++- Optionally provide an alterantive mechanism for netif queue stop/wake, ++ so that the ieee80211 layer will pass one fragment per time instead of ++ one txb struct per time. so the driver can stop the queue in the middle ++ of a packet. ++- Provide two different TX interfaces for cards that can handle management ++ frames on one HW queue, and data on another, and for cards that have only ++ one HW queue (the latter untested and very, very rough). ++- Optionally provide the logic for handling IBSS/MASTER/MONITOR/BSS modes ++ and for the channel, essid and wap get/set wireless extension requests. ++ so that the driver has only to change channel when the ieee stack tell it. ++- Optionally provide a scanning mechanism so that the driver has not to ++ worry about this, just implement the set channel calback and pass ++ frames to the upper layer ++- Optionally provide the bss client protocol handshaking (just with open ++ authentication) ++- Optionally provide the probe request send mechanism ++- Optionally provide the bss master mode logic to handle association ++ protocol (only open authentication) and probe responses. ++- SW wep encryption (with open authentication) ++- It collects some stats ++- It provides beacons to the card when it ask for them ++ ++What this layer doesn't do (yet) ++- Perform shared authentication ++- Have full support for master mode (the AP should loop back in the air ++ frames from an associated client to another. This could be done easily ++ with few lines of code, and it is done in my previous version of the ++ stach, but a table of association must be keept and a disassociation ++ policy must be decided and implemented. ++- Handle cleanly the full ieee 802.11 protocol. In AP mode it never ++ disassociate clients, and it is really prone to always allow access. ++ In bss client mode it is a bit rough with AP deauth and disassoc requests. ++- It has not any entry point to view the collected stats. ++- Altought it takes care of the card supported rates in the management frame ++ it sends, support for rate changing on TXed packet is not complete. ++- Give up once associated in bss client mode (it never detect a ++ signal loss condition to disassociate and restart scanning) ++- Provide a mechanism for enabling the TX in monitor mode, so ++ userspace programs can TX raw packets. ++- Provide a mechanism for cards that need that the SW take care of beacon ++ TX completely, in sense that the SW has to enqueue by itself beacons ++ to the card so it TX them (if any...) ++APIs ++ ++Callback functions in the original stack has been mantained. ++following has been added (from ieee80211.h) ++ ++ /* Softmac-generated frames (mamagement) are TXed via this ++ * callback if the flag IEEE_SOFTMAC_SINGLE_QUEUE is ++ * not set. As some cards may have different HW queues that ++ * one might want to use for data and management frames ++ * the option to have two callbacks might be useful. ++ * This fucntion can't sleep. ++ */ ++ int (*softmac_hard_start_xmit)(struct sk_buff *skb, ++ struct net_device *dev); ++ ++ /* used instead of hard_start_xmit (not softmac_hard_start_xmit) ++ * if the IEEE_SOFTMAC_TX_QUEUE feature is used to TX data ++ * frames. I the option IEEE_SOFTMAC_SINGLE_QUEUE is also set ++ * then also management frames are sent via this callback. ++ * This function can't sleep. ++ */ ++ void (*softmac_data_hard_start_xmit)(struct sk_buff *skb, ++ struct net_device *dev); ++ ++ /* stops the HW queue for DATA frames. Useful to avoid ++ * waste time to TX data frame when we are reassociating ++ * This function can sleep. ++ */ ++ void (*data_hard_stop)(struct net_device *dev); ++ ++ /* OK this is complementar to data_poll_hard_stop */ ++ void (*data_hard_resume)(struct net_device *dev); ++ ++ /* ask to the driver to retune the radio . ++ * This function can sleep. the driver should ensure ++ * the radio has been swithced before return. ++ */ ++ void (*set_chan)(struct net_device *dev,short ch); ++ ++ /* These are not used if the ieee stack takes care of ++ * scanning (IEEE_SOFTMAC_SCAN feature set). ++ * In this case only the set_chan is used. ++ * ++ * The syncro version is similar to the start_scan but ++ * does not return until all channels has been scanned. ++ * this is called in user context and should sleep, ++ * it is called in a work_queue when swithcing to ad-hoc mode ++ * or in behalf of iwlist scan when the card is associated ++ * and root user ask for a scan. ++ * the fucntion stop_scan should stop both the syncro and ++ * background scanning and can sleep. ++ * The fucntion start_scan should initiate the background ++ * scanning and can't sleep. ++ */ ++ void (*scan_syncro)(struct net_device *dev); ++ void (*start_scan)(struct net_device *dev); ++ void (*stop_scan)(struct net_device *dev); ++ ++ /* indicate the driver that the link state is changed ++ * for example it may indicate the card is associated now. ++ * Driver might be interested in this to apply RX filter ++ * rules or simply light the LINK led ++ */ ++ void (*link_change)(struct net_device *dev); ++ ++Functions hard_data_[resume/stop] are optional and should not be used ++if the driver decides to uses data+management frames enqueue in a ++single HQ queue (thus using just the softmac_hard_data_start_xmit ++callback). ++ ++Function that the driver can use are: ++ ++ieee80211_get_beacon - this is called by the driver when ++ the HW needs a beacon. ++ieee80211_softmac_start_protocol - this should normally be called in the ++ driver open function ++ieee80211_softmac_stop_protocol - the opposite of the above ++ieee80211_wake_queue - this is similar to netif_wake_queue ++ieee80211_reset_queue - this throw away fragments pending(if any) ++ieee80211_stop_queue - this is similar to netif_stop_queue ++ ++ ++known BUGS: ++- When performing syncro scan (possiblily when swithcing to ad-hoc mode ++ and when running iwlist scan when associated) there is still an odd ++ behaviour.. I have not looked in this more accurately (yet). ++ ++locking: ++locking is done by means of three structures. ++1- ieee->lock (by means of spin_[un]lock_irq[save/restore] ++2- ieee->wx_sem ++3- ieee->scan_sem ++ ++the lock 1 is what protect most of the critical sections in the ieee stack. ++the lock 2 is used to avoid that more than one of the SET wireless extension ++handlers (as well as start/stop protocol function) are running at the same time. ++the lock 1 is used when we need to modify or read the shared data in the wx handlers. ++In other words the lock 2 will prevent one SET action will run across another SET ++action (by make sleep the 2nd one) but allow GET actions, while the lock 1 ++make atomic those little shared data access in both GET and SET operation. ++So get operation will be never be delayed really: they will never sleep.. ++Furthermore in the top of some SET operations a flag is set before acquiring ++the lock. This is an help to make the previous running SET operation to ++finish faster if needed (just in case the second one will totally undo the ++first, so there is not need to complete the 1st really.. ). ++The background scanning mechaninsm is protected by the lock 1 except for the ++workqueue. this wq is here just to let the set_chan callback sleep (I thinked it ++might be appreciated by USB network card driver developer). In this case the lock 3 ++take its turn. ++Thus the stop function needs both the locks. ++Funny in the syncro scan the lock 2 play its role (as both the syncro_scan ++function and the stop scan function are called with this semaphore held). ++ ++ +diff -Nur linux-2.6.33/drivers/net/wireless/rtl8187b/ieee80211/rtl8187_mesh.h linux-lemote/drivers/net/wireless/rtl8187b/ieee80211/rtl8187_mesh.h +--- linux-2.6.33/drivers/net/wireless/rtl8187b/ieee80211/rtl8187_mesh.h 1970-01-01 01:00:00.000000000 +0100 ++++ linux-lemote/drivers/net/wireless/rtl8187b/ieee80211/rtl8187_mesh.h 2010-03-06 16:43:22.000000000 +0100 +@@ -0,0 +1,282 @@ ++#ifndef _RTL8187_MESH_H_
++#define _RTL8187_MESH_H_
++
++#include "msh_class.h" // struct mshclass
++#include "mesh.h" // struct MESH-Neighbor-Entry
++#include "ieee80211.h" // struct ieee80211-network
++#include "mesh_8185_util.h" // DOT11-QUEUE
++#include "hash_table.h" // hash-table
++#include "8185s_pathsel.h"
++#include <linux/list.h>
++
++#define GET_MESH_PRIV(x) ((struct mshclass_priv *)(x->priv))
++
++struct ieee80211_hdr_mesh {
++ u16 frame_ctl;
++ u16 duration_id;
++ u8 addr1[ETH_ALEN];
++ u8 addr2[ETH_ALEN];
++ u8 addr3[ETH_ALEN];
++ u16 seq_ctl;
++ u8 addr4[ETH_ALEN];
++ unsigned char mesh_flag;
++ INT8 TTL;
++ UINT16 segNum;
++ unsigned char DestMACAddr[ETH_ALEN]; // modify for 6 address
++ unsigned char SrcMACAddr[ETH_ALEN];
++} __attribute__ ((packed));
++
++struct myMeshIDNode {
++ struct list_head list;
++ char id[MESH_ID_LEN+1];
++ short popEN;
++ char tried;
++ unsigned long expire;
++ struct ieee80211_network mesh_network;
++};
++
++struct ieee80211_hdr_mesh_QOS {
++ u16 frame_ctl;
++ u16 duration_id;
++ u8 addr1[ETH_ALEN];
++ u8 addr2[ETH_ALEN];
++ u8 addr3[ETH_ALEN];
++ u16 seq_ctl;
++ u8 addr4[ETH_ALEN];
++ u16 QOS_ctl;
++ unsigned char mesh_flag;
++ INT8 TTL;
++ UINT16 segNum;
++ unsigned char DestMACAddr[ETH_ALEN]; // modify for 6 address
++ unsigned char SrcMACAddr[ETH_ALEN];
++} __attribute__ ((packed));
++
++
++struct mesh_PeerEntry {
++ // based on 8185ag.h
++ struct list_head hash_list;
++ unsigned int used; ///< used == TRUE => has been allocated, \n used == FALSE => can be allocated
++ unsigned char hwaddr[MACADDRLEN]; ///< hardware address
++
++ // struct list_head mesh_unEstablish_ptr; // ©|¥¼(©Î±q¤w³s½u -> ¥¼³s½u) ¤§ MP list
++ struct list_head mesh_mp_ptr; // MP list
++
++ /*mesh_neighbor:
++ * Inited by "Neighbor Discovering"
++ * cleaned by "Disassociation" or "Expired"
++ */
++ struct MESH_Neighbor_Entry mesh_neighbor_TBL;
++
++ struct ieee80211_network * pstat; // a backward pointer
++
++ // 802.11 seq checking
++ u16 last_rxseq; /* rx seq previous per-tid */
++ u16 last_rxfrag;/* tx frag previous per-tid */
++ unsigned long last_time;
++ //
++};
++
++
++struct mshclass_priv {
++
++ struct mesh_PeerEntry *meshEntries; // 1-to-1 for priv->ieee80211->networks
++
++ spinlock_t lock_stainfo; // lock for accessing the data structure of stat info
++ spinlock_t lock_queue; // lock for DOT11_EnQueue2/DOT11_DeQueue2/enque/dequeue
++ spinlock_t lock_Rreq; // lock for rreq_retry. Some function like aodv_expire/tx use lock_queue simultaneously
++// spinlock_t lock_meshlist;
++
++ // struct _DOT11_QUEUE *pevent_queue; ///< 802.11 QUEUEµ²ºc
++ // struct hash_table *pathsel_table; // GANTOE
++ //tsananiu
++ struct _DOT11_QUEUE *pathsel_queue; ///< 802.11 QUEUEµ²ºc
++
++ //tsananiu end
++
++ //add by shlu 20070518
++ unsigned char RreqMAC[AODV_RREQ_TABLE_SIZE][6];
++ unsigned int RreqBegin;
++ unsigned int RreqEnd;
++
++#if defined(MESH_ROLE_ROOT) || defined(MESH_ROLE_PORTAL)
++#define MAX_SZ_BAD_MAC 3
++ unsigned char BadMac[MAX_SZ_BAD_MAC][MACADDRLEN];
++ int idx_BadMac;
++#endif // MESH_ROLE_ROOT || MESH_ROLE_PORTAL
++
++ //-------------
++ unsigned char root_mac[MACADDRLEN];
++ struct mesh_info dot11MeshInfo; // extrated from wifi_mib (ieee802_mib.h)
++ struct hash_table *proxy_table, *mesh_rreq_retry_queue; //GANTOE //GANTOE
++ struct hash_table *pathsel_table; // add by chuangch 2007.09.13
++ // add by Jason
++ struct mpp_tb *pann_mpp_tb;
++
++ struct timer_list expire_timer; // 1sec timer
++
++ struct timer_list beacon_timer; // 1sec timer
++ struct list_head stat_hash[MAX_NETWORK_COUNT]; // sta_info hash table (aid_obj)
++
++ struct list_head meshList[MAX_CHANNEL_NUMBER];
++ int scanMode;
++
++ struct {
++ struct ieee80211_network *pstat;
++ unsigned char hwaddr[MACADDRLEN];
++ } stainfo_cache;
++
++ // The following elements are used by 802.11s.
++ // For copyright-pretection, we use an independent (binary) module.
++ // Note that it can also be put either under r8180_priv or ieee80211_device. The adv of put under
++ // r8180_priv is to get "higher encapsulation". On the other hand, r8180_priv was originally designed
++ // for "hardward specific."
++ char mesh_mac_filter_allow[8][13];
++ char mesh_mac_filter_deny[8][13];
++
++ struct MESH_Share meshare; // mesh share data
++
++ struct {
++
++ int prev_iw_mode; // Save this->iw_mode for r8180_wx->r8180_wx_enable_mesh. No init requirement
++
++ struct MESH_Profile mesh_profile; // contains MESHID
++
++ struct mesh_info dot11MeshInfo; // contains meshMaxAssocNum
++
++ struct net_device_stats mesh_stats;
++
++ UINT8 mesh_Version; // ¨Ï¥Îªºª©¥»
++ // WLAN Mesh Capability
++ INT16 mesh_PeerCAP_cap; // peer capability-Cap number (¦³¸¹¼Æ)
++ UINT8 mesh_PeerCAP_flags; // peer capability-flags
++ UINT8 mesh_PowerSaveCAP; // Power Save capability
++ UINT8 mesh_SyncCAP; // Synchronization capability
++ UINT8 mesh_MDA_CAP; // MDA capability
++ UINT32 mesh_ChannelPrecedence; // Channel Precedence
++
++ // neighbor -> candidate neighbor, if mesh_available_peerlink > 0, page 56, D0.02
++ UINT8 mesh_AvailablePeerLink; // ¦¹¬O§_¦³»Ýn?(¦]¥¦µ¥¦P©ó mesh_PeerCAP)=>¼È ®É«O ¯d
++
++ UINT8 mesh_HeaderFlags; // mesh header ¤ºªº mesh flags field
++
++ // MKD domain element [MKDDIE]
++ UINT8 mesh_MKD_DomainID[6];
++ UINT8 mesh_MKDDIE_SecurityConfiguration;
++
++ // EMSA Handshake element [EMSAIE]
++ UINT8 mesh_EMSAIE_ANonce[32];
++ UINT8 mesh_EMSAIE_SNonce[32];
++ UINT8 mesh_EMSAIE_MA_ID[6];
++ UINT16 mesh_EMSAIE_MIC_Control;
++ UINT8 mesh_EMSAIE_MIC[16];
++
++ struct timer_list mesh_peer_link_timer; ///< ¹ï©|¥¼³s ½u(»P³s½u°h¦Ü¥¼³s½u) MP mesh_unEstablish_hdr §@ peer link time out
++
++// struct timer_list mesh_beacon_timer;
++ // mesh_unEstablish_hdr:
++ // It is a list structure, only stores unEstablish (or Establish -> unEstablish [MP_HOLDING])MP entry
++ // Each entry is a pointer pointing to an entry in "stat_info->mesh_mp_ptr"
++ // and removed by successful "Peer link setup" or "Expired"
++ struct list_head mesh_unEstablish_hdr;
++
++ // mesh_mp_hdr:
++ // It is a list of MP/MAP/MPP who has already passed "Peer link setup"
++ // Each entry is a pointer pointing to an entry in "stat_info->mesh_mp_ptr"
++ // Every entry is inserted by "successful peer link setup"
++ // and removed by "Expired"
++ struct list_head mesh_mp_hdr;
++
++ } mesh;
++
++ int iCurChannel; // remember the working channel
++};
++
++// Stanley, 04/23/07
++// The following mode is used by ieee80211_device->iw_mode
++// Although it is better to put the definition under linux/wireless.h (or wireless_copy.h), it is a system file
++// that we shouldn't modify directly.
++#define IW_MODE_MESH 11 /* 802.11s mesh mode */
++
++// Default MESHID
++#define IEEE80211S_DEFAULT_MESHID "802.11s"
++
++// callback for 802.11s
++extern short rtl8187_patch_ieee80211_probe_req_1 (struct ieee80211_device *ieee);
++extern u8* rtl8187_patch_ieee80211_probe_req_2 (struct ieee80211_device *ieee, struct sk_buff *skb, u8 *tag);
++
++// wx
++extern int rtl8187_patch_r8180_wx_get_meshinfo(struct net_device *dev, struct iw_request_info *info, union iwreq_data *wrqu, char *extra);
++extern int rtl8187_patch_r8180_wx_enable_mesh(struct net_device *dev);
++extern int rtl8187_patch_r8180_wx_disable_mesh(struct net_device *dev);
++extern int rtl8187_patch_r8180_wx_wx_set_meshID(struct net_device *dev, char *ext,unsigned char channel);
++extern void rtl8187_patch_r8180_wx_set_channel (struct ieee80211_device *ieee, int ch);
++extern int rtl8187_patch_r8180_wx_set_add_mac_allow(struct net_device *dev, struct iw_request_info *info, union iwreq_data *wrqu, char *extra);
++extern int rtl8187_patch_r8180_wx_set_del_mac_allow(struct net_device *dev, struct iw_request_info *info, union iwreq_data *wrqu, char *extra);
++extern int rtl8187_patch_r8180_wx_set_add_mac_deny(struct net_device *dev, struct iw_request_info *info, union iwreq_data *wrqu, char *extra);
++extern int rtl8187_patch_r8180_wx_set_del_mac_deny(struct net_device *dev, struct iw_request_info *info, union iwreq_data *wrqu, char *extra);
++extern int rtl8187_patch_r8180_wx_get_mac_allow(struct net_device *dev, struct iw_request_info *info, union iwreq_data *wrqu, char *extra);
++extern int rtl8187_patch_r8180_wx_get_mac_deny(struct net_device *dev, struct iw_request_info *info, union iwreq_data *wrqu, char *extra);
++
++extern int rtl8187_patch_r8180_wx_get_mesh_list(struct net_device *dev, struct iw_request_info *info, union iwreq_data *wrqu, char *extra);
++extern int rtl8187_patch_r8180_wx_mesh_scan(struct net_device *dev, struct iw_request_info *info, union iwreq_data *wrqu, char *extra);
++extern int rtl8187_patch_r8180_wx_get_selected_mesh(struct net_device *dev, int en, char *cho, char* id);
++//by amy for networkmanager UI
++extern int rtl8187_patch_r8180_wx_get_selected_mesh_channel(struct net_device *dev, char *extmeshid, char *cho);
++//by amy for networkmanager UI
++// osdep
++extern int rtl8187_patch_ieee80211_start_protocol (struct ieee80211_device *ieee);
++extern u8 rtl8187_patch_rtl8180_up(struct mshclass *priv);
++extern void rtl8187_patch_ieee80211_stop_protocol(struct ieee80211_device *ieee);
++
++// issue_assocreq_MP
++extern void rtl8187_patch_ieee80211_association_req_1 (struct ieee80211_assoc_request_frame *hdr);
++extern u8* rtl8187_patch_ieee80211_association_req_2 (struct ieee80211_device *ieee, struct ieee80211_network *pstat, struct sk_buff *skb);
++
++// OnAssocReq_MP
++extern int rtl8187_patch_ieee80211_rx_frame_softmac_on_assoc_req (struct ieee80211_device *ieee, struct sk_buff *skb);
++
++// issue_assocrsp_MP
++extern void rtl8187_patch_ieee80211_assoc_resp_by_net_1 (struct ieee80211_assoc_response_frame *assoc);
++u8* rtl8187_patch_ieee80211_assoc_resp_by_net_2 (struct ieee80211_device *ieee, struct ieee80211_network *pstat, int pkt_type, struct sk_buff *skb);
++
++// OnAssocRsp_MP
++extern int rtl8187_patch_ieee80211_rx_frame_softmac_on_assoc_rsp (struct ieee80211_device *ieee, struct sk_buff *skb);
++
++
++extern int rtl8187_patch_ieee80211_rx_frame_softmac_on_auth(struct ieee80211_device *ieee, struct sk_buff *skb, struct ieee80211_rx_stats *rx_stats);
++extern int rtl8187_patch_ieee80211_rx_frame_softmac_on_deauth(struct ieee80211_device *ieee, struct sk_buff *skb, struct ieee80211_rx_stats *rx_stats);
++extern unsigned int rtl8187_patch_ieee80211_process_probe_response_1( struct ieee80211_device *ieee, struct ieee80211_probe_response *beacon, struct ieee80211_rx_stats *stats);
++extern void rtl8187_patch_ieee80211_rx_mgt_on_probe_req( struct ieee80211_device *ieee, struct ieee80211_probe_request *beacon, struct ieee80211_rx_stats *stats);
++extern void rtl8187_patch_ieee80211_rx_mgt_update_expire ( struct ieee80211_device *ieee, struct sk_buff *skb);
++
++// set channel
++extern int rtl8187_patch_ieee80211_ext_stop_scan_wq_set_channel (struct ieee80211_device *ieee);
++
++// on rx (rx isr)
++extern int rtl8187_patch_ieee80211_rx_on_rx (struct ieee80211_device *ieee, struct sk_buff *skb, struct ieee80211_rx_stats *rx_stats, u16 type, u16 stype);
++
++// r8187_core
++// handle ioctl
++extern int rtl8187_patch_rtl8180_ioctl(struct net_device *dev, struct ifreq *rq, int cmd);
++// create proc
++extern void rtl8187_patch_create_proc(struct r8180_priv *priv);
++extern void rtl8187_patch_remove_proc(struct r8180_priv *priv);
++
++// tx, xmit
++// locked by ieee->lock. Call ieee80211_softmac_xmit afterward
++extern struct ieee80211_txb* rtl8187_patch_ieee80211_xmit (struct sk_buff *skb, struct net_device *dev);
++
++// given a skb, output header's length
++extern int rtl8187_patch_ieee80211_rx_frame_get_hdrlen (struct ieee80211_device *ieee, struct sk_buff *skb);
++
++// check the frame control field, return 0: not accept, 1: accept
++extern int rtl8187_patch_ieee80211_rx_is_valid_framectl (struct ieee80211_device *ieee, u16 fc, u16 type, u16 stype);
++
++// process_dataframe
++extern int rtl8187_patch_ieee80211_rx_process_dataframe (struct ieee80211_device *ieee, struct sk_buff *skb, struct ieee80211_rx_stats *rx_stats);
++
++extern int rtl8187_patch_is_duplicate_packet (struct ieee80211_device *ieee, struct ieee80211_hdr *header, u16 type, u16 stype);
++
++extern int rtl8187_patch_ieee80211_softmac_xmit_get_rate (struct ieee80211_device *ieee, struct sk_buff *skb);
++extern void ieee80211_start_mesh(struct ieee80211_device *ieee);
++#endif // _RTL8187_MESH_H_
+diff -Nur linux-2.6.33/drivers/net/wireless/rtl8187b/ieee80211/rtl_crypto.h linux-lemote/drivers/net/wireless/rtl8187b/ieee80211/rtl_crypto.h +--- linux-2.6.33/drivers/net/wireless/rtl8187b/ieee80211/rtl_crypto.h 1970-01-01 01:00:00.000000000 +0100 ++++ linux-lemote/drivers/net/wireless/rtl8187b/ieee80211/rtl_crypto.h 2010-03-06 16:43:22.000000000 +0100 +@@ -0,0 +1,399 @@ ++/* ++ * Scatterlist Cryptographic API. ++ * ++ * Copyright (c) 2002 James Morris <jmorris@intercode.com.au> ++ * Copyright (c) 2002 David S. Miller (davem@redhat.com) ++ * ++ * Portions derived from Cryptoapi, by Alexander Kjeldaas <astor@fast.no> ++ * and Nettle, by Niels Mé°ˆler. ++ * ++ * This program is free software; you can redistribute it and/or modify it ++ * under the terms of the GNU General Public License as published by the Free ++ * Software Foundation; either version 2 of the License, or (at your option) ++ * any later version. ++ * ++ */ ++#ifndef _LINUX_CRYPTO_H ++#define _LINUX_CRYPTO_H ++ ++#include <linux/module.h> ++#include <linux/kernel.h> ++#include <linux/types.h> ++#include <linux/list.h> ++#include <linux/string.h> ++#include <asm/page.h> ++#include <asm/errno.h> ++ ++#define crypto_register_alg crypto_register_alg_rtl ++#define crypto_unregister_alg crypto_unregister_alg_rtl ++#define crypto_alloc_tfm crypto_alloc_tfm_rtl ++#define crypto_free_tfm crypto_free_tfm_rtl ++#define crypto_alg_available crypto_alg_available_rtl ++ ++/* ++ * Algorithm masks and types. ++ */ ++#define CRYPTO_ALG_TYPE_MASK 0x000000ff ++#define CRYPTO_ALG_TYPE_CIPHER 0x00000001 ++#define CRYPTO_ALG_TYPE_DIGEST 0x00000002 ++#define CRYPTO_ALG_TYPE_COMPRESS 0x00000004 ++ ++/* ++ * Transform masks and values (for crt_flags). ++ */ ++#define CRYPTO_TFM_MODE_MASK 0x000000ff ++#define CRYPTO_TFM_REQ_MASK 0x000fff00 ++#define CRYPTO_TFM_RES_MASK 0xfff00000 ++ ++#define CRYPTO_TFM_MODE_ECB 0x00000001 ++#define CRYPTO_TFM_MODE_CBC 0x00000002 ++#define CRYPTO_TFM_MODE_CFB 0x00000004 ++#define CRYPTO_TFM_MODE_CTR 0x00000008 ++ ++#define CRYPTO_TFM_REQ_WEAK_KEY 0x00000100 ++#define CRYPTO_TFM_RES_WEAK_KEY 0x00100000 ++#define CRYPTO_TFM_RES_BAD_KEY_LEN 0x00200000 ++#define CRYPTO_TFM_RES_BAD_KEY_SCHED 0x00400000 ++#define CRYPTO_TFM_RES_BAD_BLOCK_LEN 0x00800000 ++#define CRYPTO_TFM_RES_BAD_FLAGS 0x01000000 ++ ++/* ++ * Miscellaneous stuff. ++ */ ++#define CRYPTO_UNSPEC 0 ++#define CRYPTO_MAX_ALG_NAME 64 ++ ++struct scatterlist; ++ ++/* ++ * Algorithms: modular crypto algorithm implementations, managed ++ * via crypto_register_alg() and crypto_unregister_alg(). ++ */ ++struct cipher_alg { ++ unsigned int cia_min_keysize; ++ unsigned int cia_max_keysize; ++ int (*cia_setkey)(void *ctx, const u8 *key, ++ unsigned int keylen, u32 *flags); ++ void (*cia_encrypt)(void *ctx, u8 *dst, const u8 *src); ++ void (*cia_decrypt)(void *ctx, u8 *dst, const u8 *src); ++}; ++ ++struct digest_alg { ++ unsigned int dia_digestsize; ++ void (*dia_init)(void *ctx); ++ void (*dia_update)(void *ctx, const u8 *data, unsigned int len); ++ void (*dia_final)(void *ctx, u8 *out); ++ int (*dia_setkey)(void *ctx, const u8 *key, ++ unsigned int keylen, u32 *flags); ++}; ++ ++struct compress_alg { ++ int (*coa_init)(void *ctx); ++ void (*coa_exit)(void *ctx); ++ int (*coa_compress)(void *ctx, const u8 *src, unsigned int slen, ++ u8 *dst, unsigned int *dlen); ++ int (*coa_decompress)(void *ctx, const u8 *src, unsigned int slen, ++ u8 *dst, unsigned int *dlen); ++}; ++ ++#define cra_cipher cra_u.cipher ++#define cra_digest cra_u.digest ++#define cra_compress cra_u.compress ++ ++struct crypto_alg { ++ struct list_head cra_list; ++ u32 cra_flags; ++ unsigned int cra_blocksize; ++ unsigned int cra_ctxsize; ++ const char cra_name[CRYPTO_MAX_ALG_NAME]; ++ ++ union { ++ struct cipher_alg cipher; ++ struct digest_alg digest; ++ struct compress_alg compress; ++ } cra_u; ++ ++ struct module *cra_module; ++}; ++ ++/* ++ * Algorithm registration interface. ++ */ ++int crypto_register_alg(struct crypto_alg *alg); ++int crypto_unregister_alg(struct crypto_alg *alg); ++ ++/* ++ * Algorithm query interface. ++ */ ++int crypto_alg_available(const char *name, u32 flags); ++ ++/* ++ * Transforms: user-instantiated objects which encapsulate algorithms ++ * and core processing logic. Managed via crypto_alloc_tfm() and ++ * crypto_free_tfm(), as well as the various helpers below. ++ */ ++struct crypto_tfm; ++ ++struct cipher_tfm { ++ void *cit_iv; ++ unsigned int cit_ivsize; ++ u32 cit_mode; ++ int (*cit_setkey)(struct crypto_tfm *tfm, ++ const u8 *key, unsigned int keylen); ++ int (*cit_encrypt)(struct crypto_tfm *tfm, ++ struct scatterlist *dst, ++ struct scatterlist *src, ++ unsigned int nbytes); ++ int (*cit_encrypt_iv)(struct crypto_tfm *tfm, ++ struct scatterlist *dst, ++ struct scatterlist *src, ++ unsigned int nbytes, u8 *iv); ++ int (*cit_decrypt)(struct crypto_tfm *tfm, ++ struct scatterlist *dst, ++ struct scatterlist *src, ++ unsigned int nbytes); ++ int (*cit_decrypt_iv)(struct crypto_tfm *tfm, ++ struct scatterlist *dst, ++ struct scatterlist *src, ++ unsigned int nbytes, u8 *iv); ++ void (*cit_xor_block)(u8 *dst, const u8 *src); ++}; ++ ++struct digest_tfm { ++ void (*dit_init)(struct crypto_tfm *tfm); ++ void (*dit_update)(struct crypto_tfm *tfm, ++ struct scatterlist *sg, unsigned int nsg); ++ void (*dit_final)(struct crypto_tfm *tfm, u8 *out); ++ void (*dit_digest)(struct crypto_tfm *tfm, struct scatterlist *sg, ++ unsigned int nsg, u8 *out); ++ int (*dit_setkey)(struct crypto_tfm *tfm, ++ const u8 *key, unsigned int keylen); ++#ifdef CONFIG_CRYPTO_HMAC ++ void *dit_hmac_block; ++#endif ++}; ++ ++struct compress_tfm { ++ int (*cot_compress)(struct crypto_tfm *tfm, ++ const u8 *src, unsigned int slen, ++ u8 *dst, unsigned int *dlen); ++ int (*cot_decompress)(struct crypto_tfm *tfm, ++ const u8 *src, unsigned int slen, ++ u8 *dst, unsigned int *dlen); ++}; ++ ++#define crt_cipher crt_u.cipher ++#define crt_digest crt_u.digest ++#define crt_compress crt_u.compress ++ ++struct crypto_tfm { ++ ++ u32 crt_flags; ++ ++ union { ++ struct cipher_tfm cipher; ++ struct digest_tfm digest; ++ struct compress_tfm compress; ++ } crt_u; ++ ++ struct crypto_alg *__crt_alg; ++}; ++ ++/* ++ * Transform user interface. ++ */ ++ ++/* ++ * crypto_alloc_tfm() will first attempt to locate an already loaded algorithm. ++ * If that fails and the kernel supports dynamically loadable modules, it ++ * will then attempt to load a module of the same name or alias. A refcount ++ * is grabbed on the algorithm which is then associated with the new transform. ++ * ++ * crypto_free_tfm() frees up the transform and any associated resources, ++ * then drops the refcount on the associated algorithm. ++ */ ++struct crypto_tfm *crypto_alloc_tfm(const char *alg_name, u32 tfm_flags); ++void crypto_free_tfm(struct crypto_tfm *tfm); ++ ++/* ++ * Transform helpers which query the underlying algorithm. ++ */ ++static inline const char *crypto_tfm_alg_name(struct crypto_tfm *tfm) ++{ ++ return tfm->__crt_alg->cra_name; ++} ++ ++static inline const char *crypto_tfm_alg_modname(struct crypto_tfm *tfm) ++{ ++ struct crypto_alg *alg = tfm->__crt_alg; ++ ++ if (alg->cra_module) ++ return alg->cra_module->name; ++ else ++ return NULL; ++} ++ ++static inline u32 crypto_tfm_alg_type(struct crypto_tfm *tfm) ++{ ++ return tfm->__crt_alg->cra_flags & CRYPTO_ALG_TYPE_MASK; ++} ++ ++static inline unsigned int crypto_tfm_alg_min_keysize(struct crypto_tfm *tfm) ++{ ++ BUG_ON(crypto_tfm_alg_type(tfm) != CRYPTO_ALG_TYPE_CIPHER); ++ return tfm->__crt_alg->cra_cipher.cia_min_keysize; ++} ++ ++static inline unsigned int crypto_tfm_alg_max_keysize(struct crypto_tfm *tfm) ++{ ++ BUG_ON(crypto_tfm_alg_type(tfm) != CRYPTO_ALG_TYPE_CIPHER); ++ return tfm->__crt_alg->cra_cipher.cia_max_keysize; ++} ++ ++static inline unsigned int crypto_tfm_alg_ivsize(struct crypto_tfm *tfm) ++{ ++ BUG_ON(crypto_tfm_alg_type(tfm) != CRYPTO_ALG_TYPE_CIPHER); ++ return tfm->crt_cipher.cit_ivsize; ++} ++ ++static inline unsigned int crypto_tfm_alg_blocksize(struct crypto_tfm *tfm) ++{ ++ return tfm->__crt_alg->cra_blocksize; ++} ++ ++static inline unsigned int crypto_tfm_alg_digestsize(struct crypto_tfm *tfm) ++{ ++ BUG_ON(crypto_tfm_alg_type(tfm) != CRYPTO_ALG_TYPE_DIGEST); ++ return tfm->__crt_alg->cra_digest.dia_digestsize; ++} ++ ++/* ++ * API wrappers. ++ */ ++static inline void crypto_digest_init(struct crypto_tfm *tfm) ++{ ++ BUG_ON(crypto_tfm_alg_type(tfm) != CRYPTO_ALG_TYPE_DIGEST); ++ tfm->crt_digest.dit_init(tfm); ++} ++ ++static inline void crypto_digest_update(struct crypto_tfm *tfm, ++ struct scatterlist *sg, ++ unsigned int nsg) ++{ ++ BUG_ON(crypto_tfm_alg_type(tfm) != CRYPTO_ALG_TYPE_DIGEST); ++ tfm->crt_digest.dit_update(tfm, sg, nsg); ++} ++ ++static inline void crypto_digest_final(struct crypto_tfm *tfm, u8 *out) ++{ ++ BUG_ON(crypto_tfm_alg_type(tfm) != CRYPTO_ALG_TYPE_DIGEST); ++ tfm->crt_digest.dit_final(tfm, out); ++} ++ ++static inline void crypto_digest_digest(struct crypto_tfm *tfm, ++ struct scatterlist *sg, ++ unsigned int nsg, u8 *out) ++{ ++ BUG_ON(crypto_tfm_alg_type(tfm) != CRYPTO_ALG_TYPE_DIGEST); ++ tfm->crt_digest.dit_digest(tfm, sg, nsg, out); ++} ++ ++static inline int crypto_digest_setkey(struct crypto_tfm *tfm, ++ const u8 *key, unsigned int keylen) ++{ ++ BUG_ON(crypto_tfm_alg_type(tfm) != CRYPTO_ALG_TYPE_DIGEST); ++ if (tfm->crt_digest.dit_setkey == NULL) ++ return -ENOSYS; ++ return tfm->crt_digest.dit_setkey(tfm, key, keylen); ++} ++ ++static inline int crypto_cipher_setkey(struct crypto_tfm *tfm, ++ const u8 *key, unsigned int keylen) ++{ ++ BUG_ON(crypto_tfm_alg_type(tfm) != CRYPTO_ALG_TYPE_CIPHER); ++ return tfm->crt_cipher.cit_setkey(tfm, key, keylen); ++} ++ ++static inline int crypto_cipher_encrypt(struct crypto_tfm *tfm, ++ struct scatterlist *dst, ++ struct scatterlist *src, ++ unsigned int nbytes) ++{ ++ BUG_ON(crypto_tfm_alg_type(tfm) != CRYPTO_ALG_TYPE_CIPHER); ++ return tfm->crt_cipher.cit_encrypt(tfm, dst, src, nbytes); ++} ++ ++static inline int crypto_cipher_encrypt_iv(struct crypto_tfm *tfm, ++ struct scatterlist *dst, ++ struct scatterlist *src, ++ unsigned int nbytes, u8 *iv) ++{ ++ BUG_ON(crypto_tfm_alg_type(tfm) != CRYPTO_ALG_TYPE_CIPHER); ++ BUG_ON(tfm->crt_cipher.cit_mode == CRYPTO_TFM_MODE_ECB); ++ return tfm->crt_cipher.cit_encrypt_iv(tfm, dst, src, nbytes, iv); ++} ++ ++static inline int crypto_cipher_decrypt(struct crypto_tfm *tfm, ++ struct scatterlist *dst, ++ struct scatterlist *src, ++ unsigned int nbytes) ++{ ++ BUG_ON(crypto_tfm_alg_type(tfm) != CRYPTO_ALG_TYPE_CIPHER); ++ return tfm->crt_cipher.cit_decrypt(tfm, dst, src, nbytes); ++} ++ ++static inline int crypto_cipher_decrypt_iv(struct crypto_tfm *tfm, ++ struct scatterlist *dst, ++ struct scatterlist *src, ++ unsigned int nbytes, u8 *iv) ++{ ++ BUG_ON(crypto_tfm_alg_type(tfm) != CRYPTO_ALG_TYPE_CIPHER); ++ BUG_ON(tfm->crt_cipher.cit_mode == CRYPTO_TFM_MODE_ECB); ++ return tfm->crt_cipher.cit_decrypt_iv(tfm, dst, src, nbytes, iv); ++} ++ ++static inline void crypto_cipher_set_iv(struct crypto_tfm *tfm, ++ const u8 *src, unsigned int len) ++{ ++ BUG_ON(crypto_tfm_alg_type(tfm) != CRYPTO_ALG_TYPE_CIPHER); ++ memcpy(tfm->crt_cipher.cit_iv, src, len); ++} ++ ++static inline void crypto_cipher_get_iv(struct crypto_tfm *tfm, ++ u8 *dst, unsigned int len) ++{ ++ BUG_ON(crypto_tfm_alg_type(tfm) != CRYPTO_ALG_TYPE_CIPHER); ++ memcpy(dst, tfm->crt_cipher.cit_iv, len); ++} ++ ++static inline int crypto_comp_compress(struct crypto_tfm *tfm, ++ const u8 *src, unsigned int slen, ++ u8 *dst, unsigned int *dlen) ++{ ++ BUG_ON(crypto_tfm_alg_type(tfm) != CRYPTO_ALG_TYPE_COMPRESS); ++ return tfm->crt_compress.cot_compress(tfm, src, slen, dst, dlen); ++} ++ ++static inline int crypto_comp_decompress(struct crypto_tfm *tfm, ++ const u8 *src, unsigned int slen, ++ u8 *dst, unsigned int *dlen) ++{ ++ BUG_ON(crypto_tfm_alg_type(tfm) != CRYPTO_ALG_TYPE_COMPRESS); ++ return tfm->crt_compress.cot_decompress(tfm, src, slen, dst, dlen); ++} ++ ++/* ++ * HMAC support. ++ */ ++#ifdef CONFIG_CRYPTO_HMAC ++void crypto_hmac_init(struct crypto_tfm *tfm, u8 *key, unsigned int *keylen); ++void crypto_hmac_update(struct crypto_tfm *tfm, ++ struct scatterlist *sg, unsigned int nsg); ++void crypto_hmac_final(struct crypto_tfm *tfm, u8 *key, ++ unsigned int *keylen, u8 *out); ++void crypto_hmac(struct crypto_tfm *tfm, u8 *key, unsigned int *keylen, ++ struct scatterlist *sg, unsigned int nsg, u8 *out); ++#endif /* CONFIG_CRYPTO_HMAC */ ++ ++#endif /* _LINUX_CRYPTO_H */ ++ +diff -Nur linux-2.6.33/drivers/net/wireless/rtl8187b/ieee80211/scatterwalk.h linux-lemote/drivers/net/wireless/rtl8187b/ieee80211/scatterwalk.h +--- linux-2.6.33/drivers/net/wireless/rtl8187b/ieee80211/scatterwalk.h 1970-01-01 01:00:00.000000000 +0100 ++++ linux-lemote/drivers/net/wireless/rtl8187b/ieee80211/scatterwalk.h 2010-03-06 16:43:22.000000000 +0100 +@@ -0,0 +1,51 @@ ++/* ++ * Cryptographic API. ++ * ++ * Copyright (c) 2002 James Morris <jmorris@intercode.com.au> ++ * Copyright (c) 2002 Adam J. Richter <adam@yggdrasil.com> ++ * Copyright (c) 2004 Jean-Luc Cooke <jlcooke@certainkey.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. ++ * ++ */ ++ ++#ifndef _CRYPTO_SCATTERWALK_H ++#define _CRYPTO_SCATTERWALK_H ++#include <linux/mm.h> ++#include <asm/scatterlist.h> ++ ++struct scatter_walk { ++ struct scatterlist *sg; ++ struct page *page; ++ void *data; ++ unsigned int len_this_page; ++ unsigned int len_this_segment; ++ unsigned int offset; ++}; ++ ++/* Define sg_next is an inline routine now in case we want to change ++ scatterlist to a linked list later. */ ++static inline struct scatterlist *sg_next(struct scatterlist *sg) ++{ ++ return sg + 1; ++} ++ ++static inline int scatterwalk_samebuf(struct scatter_walk *walk_in, ++ struct scatter_walk *walk_out, ++ void *src_p, void *dst_p) ++{ ++ return walk_in->page == walk_out->page && ++ walk_in->offset == walk_out->offset && ++ walk_in->data == src_p && walk_out->data == dst_p; ++} ++ ++void *scatterwalk_whichbuf(struct scatter_walk *walk, unsigned int nbytes, void *scratch); ++void scatterwalk_start(struct scatter_walk *walk, struct scatterlist *sg); ++int scatterwalk_copychunks(void *buf, struct scatter_walk *walk, size_t nbytes, int out); ++void scatterwalk_map(struct scatter_walk *walk, int out); ++void scatterwalk_done(struct scatter_walk *walk, int out, int more); ++ ++#endif /* _CRYPTO_SCATTERWALK_H */ +diff -Nur linux-2.6.33/drivers/net/wireless/rtl8187b/Makefile linux-lemote/drivers/net/wireless/rtl8187b/Makefile +--- linux-2.6.33/drivers/net/wireless/rtl8187b/Makefile 1970-01-01 01:00:00.000000000 +0100 ++++ linux-lemote/drivers/net/wireless/rtl8187b/Makefile 2010-03-06 16:43:22.000000000 +0100 +@@ -0,0 +1,41 @@ ++obj-$(CONFIG_RTL8187B) += rtl8187b.o ++ ++rtl8187b-objs := r8187_core.o \ ++ r8180_93cx6.o \ ++ r8180_wx.o \ ++ r8180_rtl8225.o \ ++ r8180_rtl8225z2.o \ ++ r8180_pm.o \ ++ r8180_dm.o \ ++ r8187_led.o \ ++ r8187_rfkill.o \ ++ ieee80211/dot11d.o \ ++ ieee80211/ieee80211_softmac.o \ ++ ieee80211/ieee80211_rx.o \ ++ ieee80211/ieee80211_tx.o \ ++ ieee80211/ieee80211_wx.o \ ++ ieee80211/ieee80211_module.o \ ++ ieee80211/ieee80211_softmac_wx.o \ ++ ieee80211/ieee80211_crypt.o \ ++ ieee80211/ieee80211_crypt_tkip.o \ ++ ieee80211/ieee80211_crypt_ccmp.o \ ++ ieee80211/ieee80211_crypt_wep.o ++ ++EXTRA_CFLAGS += -DCONFIG_RTL8180_PM ++EXTRA_CFLAGS += -DJACKSON_NEW_8187 -DJACKSON_NEW_RX ++EXTRA_CFLAGS += -DTHOMAS_BEACON -DTHOMAS_TASKLET -DTHOMAS_SKB -DTHOMAS_TURBO ++EXTRA_CFLAGS += -DJOHN_IOCTL ++EXTRA_CFLAGS += -DLED ++#EXTRA_CFLAGS += -DLED_SHIN ++#EXTRA_CFLAGS += -DSW_ANTE_DIVERSITY ++EXTRA_CFLAGS += -DCPU_64BIT ++EXTRA_CFLAGS += -DCONFIG_IPS ++#CFLAGS += -DJOHN_HWSEC -DJOHN_TKIP ++#CFLAGS += -DJOHN_DUMP_TX ++#EXTRA_CFLAGS += -DJOHN_DUMP_TXPKT ++ ++#Radio On/Off debug ++#EXTRA_CFLAGS += -DCONFIG_RADIO_DEBUG ++ ++#for dot11d ++EXTRA_CFLAGS += -DENABLE_DOT11D +diff -Nur linux-2.6.33/drivers/net/wireless/rtl8187b/msh_class.h linux-lemote/drivers/net/wireless/rtl8187b/msh_class.h +--- linux-2.6.33/drivers/net/wireless/rtl8187b/msh_class.h 1970-01-01 01:00:00.000000000 +0100 ++++ linux-lemote/drivers/net/wireless/rtl8187b/msh_class.h 2010-03-06 16:43:22.000000000 +0100 +@@ -0,0 +1,117 @@ ++/*! \file msh_class.h
++ \brief msh CLASS extension
++
++ \date 2007/5/2
++ \author Stanley Chang <chagnsl@cs.nctu.edu.tw>
++*/
++
++#ifndef _MESH_CLASS_HDR_H_
++#define _MESH_CLASS_HDR_H_
++
++#include <linux/if_ether.h> /* ETH_ALEN */
++#include <linux/kernel.h> /* ARRAY_SIZE */
++#include <linux/version.h>
++#include <linux/jiffies.h>
++#include <linux/timer.h>
++#include <linux/sched.h>
++
++#include "ieee80211/ieee80211.h" // for struct ieee80211-xxxx
++#include "r8187.h" // for struct r8180-priv
++
++#define MAC_TABLE_SIZE 8
++
++struct mshclass {
++ struct r8180_priv * p8187;
++
++ // callback functions
++ // ieee80211_softmac.c
++ int (*ext_patch_ieee80211_start_protocol) (struct ieee80211_device *ieee); // start special mode
++
++ short (*ext_patch_ieee80211_probe_req_1) (struct ieee80211_device *ieee); // return = 0: no more phases, >0: another phase
++ u8* (*ext_patch_ieee80211_probe_req_2) (struct ieee80211_device *ieee, struct sk_buff *skb, u8 *tag); // return tag
++
++ void (*ext_patch_ieee80211_association_req_1) (struct ieee80211_assoc_request_frame *hdr);
++ u8* (*ext_patch_ieee80211_association_req_2) (struct ieee80211_device *ieee, struct ieee80211_network *pstat, struct sk_buff *skb);
++
++ int (*ext_patch_ieee80211_rx_frame_softmac_on_assoc_req) (struct ieee80211_device *ieee, struct sk_buff *skb);
++ int (*ext_patch_ieee80211_rx_frame_softmac_on_assoc_rsp) (struct ieee80211_device *ieee, struct sk_buff *skb);
++
++ void (*ext_patch_ieee80211_stop_protocol) (struct ieee80211_device *ieee); // stop timer
++
++ void (*ext_patch_ieee80211_assoc_resp_by_net_1) (struct ieee80211_assoc_response_frame *assoc);
++ u8* (*ext_patch_ieee80211_assoc_resp_by_net_2) (struct ieee80211_device *ieee, struct ieee80211_network *pstat, int pkt_type, struct sk_buff *skb);
++
++ int (*ext_patch_ieee80211_ext_stop_scan_wq_set_channel) (struct ieee80211_device *ieee);
++
++ struct sk_buff* (*ext_patch_get_beacon_get_probersp)(struct ieee80211_device *ieee, u8 *dest, struct ieee80211_network *net);
++
++ int (*ext_patch_ieee80211_softmac_xmit_get_rate) (struct ieee80211_device *ieee, struct sk_buff *skb);
++ int (*ext_patch_ieee80211_rx_frame_softmac_on_auth)(struct ieee80211_device *ieee, struct sk_buff *skb, struct ieee80211_rx_stats *rx_stats);
++ int (*ext_patch_ieee80211_rx_frame_softmac_on_deauth)(struct ieee80211_device *ieee, struct sk_buff *skb, struct ieee80211_rx_stats *rx_stats);
++//by amy for mesh
++ void (*ext_patch_ieee80211_start_mesh)(struct ieee80211_device *ieee);
++//by amy for mesh
++ /// r8180_wx.c
++ int (*ext_patch_r8180_wx_get_meshinfo) (struct net_device *dev, struct iw_request_info *info, union iwreq_data *wrqu, char *extra);
++ int (*ext_patch_r8180_wx_enable_mesh) (struct net_device *dev);
++ int (*ext_patch_r8180_wx_disable_mesh) (struct net_device *dev);
++ int (*ext_patch_r8180_wx_set_meshID) ( struct net_device *dev, char *ext);
++//by amy for mesh
++ int (*ext_patch_r8180_wx_set_mesh_chan)(struct net_device *dev, unsigned char channel);
++//by amy for mesh
++ void (*ext_patch_r8180_wx_set_channel) (struct ieee80211_device *ieee, int ch);
++
++ int (*ext_patch_r8180_wx_set_add_mac_allow) (struct net_device *dev, struct iw_request_info *info, union iwreq_data *wrqu, char *extra);
++ int (*ext_patch_r8180_wx_set_del_mac_allow) (struct net_device *dev, struct iw_request_info *info, union iwreq_data *wrqu, char *extra);
++ int (*ext_patch_r8180_wx_set_add_mac_deny) (struct net_device *dev, struct iw_request_info *info, union iwreq_data *wrqu, char *extra);
++ int (*ext_patch_r8180_wx_set_del_mac_deny) (struct net_device *dev, struct iw_request_info *info, union iwreq_data *wrqu, char *extra);
++ int (*ext_patch_r8180_wx_get_mac_allow) (struct net_device *dev, struct iw_request_info *info, union iwreq_data *wrqu, char *extra);
++ int (*ext_patch_r8180_wx_get_mac_deny) (struct net_device *dev, struct iw_request_info *info, union iwreq_data *wrqu, char *extra);
++
++ int (*ext_patch_r8180_wx_get_mesh_list) (struct net_device *dev, struct iw_request_info *info, union iwreq_data *wrqu, char *extra);
++ int (*ext_patch_r8180_wx_mesh_scan) (struct net_device *dev, struct iw_request_info *info, union iwreq_data *wrqu, char *extra);
++ int (*ext_patch_r8180_wx_get_selected_mesh)(struct net_device *dev, int en, char *cho, char* id);
++//by amy for networkmanager UI
++ int (*ext_patch_r8180_wx_get_selected_mesh_channel)(struct net_device *dev, char* extmeshid, char *cho);
++//by amy for networkmanager UI
++ /// r8187_core.c
++ u8 (*ext_patch_rtl8180_up) (struct mshclass *priv);
++
++ // ieee80211_rx.c
++ unsigned int (*ext_patch_ieee80211_process_probe_response_1) ( struct ieee80211_device *ieee, struct ieee80211_probe_response *beacon, struct ieee80211_rx_stats *stats);
++ void (*ext_patch_ieee80211_rx_mgt_on_probe_req) ( struct ieee80211_device *ieee, struct ieee80211_probe_request *beacon, struct ieee80211_rx_stats *stats);
++
++ void (*ext_patch_ieee80211_rx_mgt_update_expire) ( struct ieee80211_device *ieee, struct sk_buff *skb);
++
++ int (*ext_patch_ieee80211_rx_on_rx) (struct ieee80211_device *ieee, struct sk_buff *skb, struct ieee80211_rx_stats *rx_stats, u16 type, u16 stype);
++
++ int (*ext_patch_ieee80211_rx_frame_get_hdrlen) (struct ieee80211_device *ieee, struct sk_buff *skb);
++
++ int (*ext_patch_ieee80211_rx_is_valid_framectl) (struct ieee80211_device *ieee, u16 fc, u16 type, u16 stype);
++
++ // return > 0 is success. 0 when failed
++ int (*ext_patch_ieee80211_rx_process_dataframe) (struct ieee80211_device *ieee, struct sk_buff *skb, struct ieee80211_rx_stats *rx_stats);
++
++ int (*ext_patch_is_duplicate_packet) (struct ieee80211_device *ieee, struct ieee80211_hdr *header, u16 type, u16 stype);
++ /* added by david for setting acl dynamically */
++ u8 (*ext_patch_ieee80211_acl_query) (struct ieee80211_device *ieee, u8 *sa);
++
++ // r8187_core.c
++ int (*ext_patch_rtl8180_ioctl) (struct net_device *dev, struct ifreq *rq, int cmd);
++ void (*ext_patch_create_proc) (struct r8180_priv *priv);
++ void (*ext_patch_remove_proc) (struct r8180_priv *priv);
++
++ // ieee80211_tx.c
++
++ // locked by ieee->lock. Call ieee80211_softmac_xmit afterward
++ struct ieee80211_txb* (*ext_patch_ieee80211_xmit) (struct sk_buff *skb, struct net_device *dev);
++
++ // DO NOT MODIFY ANY STRUCTURE BELOW THIS LINE
++ u8 priv[0]; // mshclass_priv;
++};
++
++extern void free_mshobj(struct mshclass **pObj);
++extern struct mshclass *alloc_mshobj(struct r8180_priv *caller_priv);
++
++
++#endif // _MESH_CLASS_HDR_H_
+diff -Nur linux-2.6.33/drivers/net/wireless/rtl8187b/r8180_93cx6.c linux-lemote/drivers/net/wireless/rtl8187b/r8180_93cx6.c +--- linux-2.6.33/drivers/net/wireless/rtl8187b/r8180_93cx6.c 1970-01-01 01:00:00.000000000 +0100 ++++ linux-lemote/drivers/net/wireless/rtl8187b/r8180_93cx6.c 2010-03-06 16:43:22.000000000 +0100 +@@ -0,0 +1,146 @@ ++/* ++ This files contains card eeprom (93c46 or 93c56) programming routines, ++ memory is addressed by 16 bits words. ++ ++ This is part of rtl8180 OpenSource driver. ++ Copyright (C) Andrea Merello 2004 <andreamrl@tiscali.it> ++ Released under the terms of GPL (General Public Licence) ++ ++ Parts of this driver are based on the GPL part of the ++ official realtek driver. ++ ++ Parts of this driver are based on the rtl8180 driver skeleton ++ from Patric Schenke & Andres Salomon. ++ ++ Parts of this driver are based on the Intel Pro Wireless 2100 GPL driver. ++ ++ We want to tanks the Authors of those projects and the Ndiswrapper ++ project Authors. ++*/ ++ ++#include "r8180_93cx6.h" ++ ++void eprom_cs(struct net_device *dev, short bit) ++{ ++ if(bit) ++ write_nic_byte(dev, EPROM_CMD, ++ (1<<EPROM_CS_SHIFT) | \ ++ read_nic_byte(dev, EPROM_CMD)); //enable EPROM ++ else ++ write_nic_byte(dev, EPROM_CMD, read_nic_byte(dev, EPROM_CMD)\ ++ &~(1<<EPROM_CS_SHIFT)); //disable EPROM ++ ++ force_pci_posting(dev); ++ udelay(EPROM_DELAY); ++} ++ ++ ++void eprom_ck_cycle(struct net_device *dev) ++{ ++ write_nic_byte(dev, EPROM_CMD, ++ (1<<EPROM_CK_SHIFT) | read_nic_byte(dev,EPROM_CMD)); ++ force_pci_posting(dev); ++ udelay(EPROM_DELAY); ++ write_nic_byte(dev, EPROM_CMD, ++ read_nic_byte(dev, EPROM_CMD) &~ (1<<EPROM_CK_SHIFT)); ++ force_pci_posting(dev); ++ udelay(EPROM_DELAY); ++} ++ ++ ++void eprom_w(struct net_device *dev,short bit) ++{ ++ if(bit) ++ write_nic_byte(dev, EPROM_CMD, (1<<EPROM_W_SHIFT) | \ ++ read_nic_byte(dev,EPROM_CMD)); ++ else ++ write_nic_byte(dev, EPROM_CMD, read_nic_byte(dev,EPROM_CMD)\ ++ &~(1<<EPROM_W_SHIFT)); ++ ++ force_pci_posting(dev); ++ udelay(EPROM_DELAY); ++} ++ ++ ++short eprom_r(struct net_device *dev) ++{ ++ short bit; ++ ++ bit=(read_nic_byte(dev, EPROM_CMD) & (1<<EPROM_R_SHIFT) ); ++ udelay(EPROM_DELAY); ++ ++ if(bit) return 1; ++ return 0; ++} ++ ++ ++void eprom_send_bits_string(struct net_device *dev, short b[], int len) ++{ ++ int i; ++ ++ for(i=0; i<len; i++){ ++ eprom_w(dev, b[i]); ++ eprom_ck_cycle(dev); ++ } ++} ++ ++ ++u32 eprom_read(struct net_device *dev, u32 addr) ++{ ++ struct r8180_priv *priv = ieee80211_priv(dev); ++ short read_cmd[]={1,1,0}; ++ short addr_str[8]; ++ int i; ++ int addr_len; ++ u32 ret; ++ ++ ret=0; ++ //enable EPROM programming ++ write_nic_byte(dev, EPROM_CMD, ++ (EPROM_CMD_PROGRAM<<EPROM_CMD_OPERATING_MODE_SHIFT)); ++ force_pci_posting(dev); ++ udelay(EPROM_DELAY); ++ ++ if (priv->epromtype==EPROM_93c56){ ++ addr_str[7]=addr & 1; ++ addr_str[6]=addr & (1<<1); ++ addr_str[5]=addr & (1<<2); ++ addr_str[4]=addr & (1<<3); ++ addr_str[3]=addr & (1<<4); ++ addr_str[2]=addr & (1<<5); ++ addr_str[1]=addr & (1<<6); ++ addr_str[0]=addr & (1<<7); ++ addr_len=8; ++ }else{ ++ addr_str[5]=addr & 1; ++ addr_str[4]=addr & (1<<1); ++ addr_str[3]=addr & (1<<2); ++ addr_str[2]=addr & (1<<3); ++ addr_str[1]=addr & (1<<4); ++ addr_str[0]=addr & (1<<5); ++ addr_len=6; ++ } ++ eprom_cs(dev, 1); ++ eprom_ck_cycle(dev); ++ eprom_send_bits_string(dev, read_cmd, 3); ++ eprom_send_bits_string(dev, addr_str, addr_len); ++ ++ //keep chip pin D to low state while reading. ++ //I'm unsure if it is necessary, but anyway shouldn't hurt ++ eprom_w(dev, 0); ++ ++ for(i=0;i<16;i++){ ++ //eeprom needs a clk cycle between writing opcode&adr ++ //and reading data. (eeprom outs a dummy 0) ++ eprom_ck_cycle(dev); ++ ret |= (eprom_r(dev)<<(15-i)); ++ } ++ ++ eprom_cs(dev, 0); ++ eprom_ck_cycle(dev); ++ ++ //disable EPROM programming ++ write_nic_byte(dev, EPROM_CMD, ++ (EPROM_CMD_NORMAL<<EPROM_CMD_OPERATING_MODE_SHIFT)); ++ return ret; ++} +diff -Nur linux-2.6.33/drivers/net/wireless/rtl8187b/r8180_93cx6.h linux-lemote/drivers/net/wireless/rtl8187b/r8180_93cx6.h +--- linux-2.6.33/drivers/net/wireless/rtl8187b/r8180_93cx6.h 1970-01-01 01:00:00.000000000 +0100 ++++ linux-lemote/drivers/net/wireless/rtl8187b/r8180_93cx6.h 2010-03-06 16:43:22.000000000 +0100 +@@ -0,0 +1,46 @@ ++/* ++ This is part of rtl8187 OpenSource driver ++ Copyright (C) Andrea Merello 2004-2005 <andreamrl@tiscali.it> ++ Released under the terms of GPL (General Public Licence) ++ ++ Parts of this driver are based on the GPL part of the official realtek driver ++ Parts of this driver are based on the rtl8180 driver skeleton from Patric Schenke & Andres Salomon ++ Parts of this driver are based on the Intel Pro Wireless 2100 GPL driver ++ ++ We want to tanks the Authors of such projects and the Ndiswrapper project Authors. ++*/ ++ ++/*This files contains card eeprom (93c46 or 93c56) programming routines*/ ++/*memory is addressed by WORDS*/ ++ ++#include "r8187.h" ++#include "r8180_hw.h" ++ ++#define EPROM_DELAY 10 ++ ++#define EPROM_ANAPARAM_ADDRLWORD 0xd ++#define EPROM_ANAPARAM_ADDRHWORD 0xe ++ ++#define EPROM_CHANNEL_PLAN 0x3 //0x6>>1 ++//0x77 BIT[0]0:use gpio 1 bit 1, 1:use gpio 1 bit 2. ++#define EPROM_SELECT_GPIO (0x77 >> 1) ++//#define EEPROM_COUNTRY_CODE 0x2E//87se channel plan is here ++ ++#define EPROM_RFCHIPID 0x6 ++#define EPROM_TXPW_BASE 0x05 ++#define EPROM_RFCHIPID_RTL8225U 5 ++#define EPROM_RFCHIPID_RTL8225U_VF 6 ++#define EPROM_RF_PARAM 0x4 ++#define EPROM_CONFIG2 0xc ++ ++#define EPROM_VERSION 0x1E ++#define MAC_ADR 0x7 ++ ++#define CIS 0x18 ++ ++#define EPROM_TXPW0 0x16 ++#define EPROM_TXPW2 0x1b ++#define EPROM_TXPW1 0x3d ++ ++ ++u32 eprom_read(struct net_device *dev,u32 addr); //reads a 16 bits word +diff -Nur linux-2.6.33/drivers/net/wireless/rtl8187b/r8180_dm.c linux-lemote/drivers/net/wireless/rtl8187b/r8180_dm.c +--- linux-2.6.33/drivers/net/wireless/rtl8187b/r8180_dm.c 1970-01-01 01:00:00.000000000 +0100 ++++ linux-lemote/drivers/net/wireless/rtl8187b/r8180_dm.c 2010-03-06 16:43:22.000000000 +0100 +@@ -0,0 +1,882 @@ ++/*++ ++Copyright (c) Realtek Semiconductor Corp. All rights reserved. ++ ++Module Name: ++ r8180_dig.c ++ ++Abstract: ++ Hardware dynamic mechanism for RTL8187B ++ ++Major Change History: ++ When Who What ++ ---------- --------------- ------------------------------- ++ 2006-11-15 david Created ++ ++Notes: ++ This file is ported from RTL8187B Windows driver. ++ ++ ++--*/ ++#include "r8180_dm.h" ++#include "r8180_hw.h" ++#include "r8180_rtl8225.h" ++ ++//================================================================================ ++// Local Constant. ++//================================================================================ ++#define Z1_HIPWR_UPPER_TH 99 ++#define Z1_HIPWR_LOWER_TH 70 ++#define Z2_HIPWR_UPPER_TH 99 ++#define Z2_HIPWR_LOWER_TH 90 ++ ++bool CheckDig(struct net_device *dev) ++{ ++ struct r8180_priv *priv = (struct r8180_priv *)ieee80211_priv(dev); ++ struct ieee80211_device *ieee = priv->ieee80211; ++ ++ if(ieee->state != IEEE80211_LINKED) ++ return false; ++ ++ if(priv->card_8187 == NIC_8187B) { ++ // ++ // We need to schedule dig workitem on either of the below mechanisms. ++ // By Bruce, 2007-06-01. ++ // ++ if(!priv->bDigMechanism && !priv->bCCKThMechanism) ++ return false; ++ ++ if(priv->CurrentOperaRate < 36) // Schedule Dig under all OFDM rates. By Bruce, 2007-06-01. ++ return false; ++ } else { ++ if(!priv->bDigMechanism) ++ return false; ++ ++ if(priv->CurrentOperaRate < 48) ++ return false; ++ } ++ return true; ++} ++ ++ ++// ++// Description: ++// Implementation of DIG for Zebra and Zebra2. ++// ++void DIG_Zebra(struct net_device *dev) ++{ ++ struct r8180_priv *priv = (struct r8180_priv *)ieee80211_priv(dev); ++ //PHAL_DATA_8187 pHalData = GetHalData8187(Adapter); ++ u16 CCKFalseAlarm, OFDMFalseAlarm; ++ u16 OfdmFA1, OfdmFA2; ++ int InitialGainStep = 7; // The number of initial gain stages. ++ int LowestGainStage = 4; // The capable lowest stage of performing dig workitem. ++ ++// printk("---------> DIG_Zebra()\n"); ++ ++ //Read only 1 byte because of HW bug. This is a temporal modification. Joseph ++ // Modify by Isaiah 2006-06-27 ++ if(priv->card_8187_Bversion == VERSION_8187B_B) ++ { ++ CCKFalseAlarm = 0; ++ OFDMFalseAlarm = (u16)(priv->FalseAlarmRegValue); ++ OfdmFA1 = 0x01; ++ OfdmFA2 = priv->RegDigOfdmFaUpTh; ++ } ++ else ++ { ++ CCKFalseAlarm = (u16)(priv->FalseAlarmRegValue & 0x0000ffff); ++ OFDMFalseAlarm = (u16)((priv->FalseAlarmRegValue >> 16) & 0x0000ffff); ++ OfdmFA1 = 0x15; ++ //OfdmFA2 = 0xC00; ++ OfdmFA2 = ((u16)(priv->RegDigOfdmFaUpTh)) << 8; ++ } ++ ++// printk("DIG**********CCK False Alarm: %#X \n",CCKFalseAlarm); ++// printk("DIG**********OFDM False Alarm: %#X \n",OFDMFalseAlarm); ++ ++ ++ ++ // The number of initial gain steps is different, by Bruce, 2007-04-13. ++ if(priv->card_8187 == NIC_8187) { ++ if (priv->InitialGain == 0 ) //autoDIG ++ { ++ switch( priv->rf_chip) ++ { ++ case RF_ZEBRA: ++ priv->InitialGain = 5; // m74dBm; ++ break; ++ case RF_ZEBRA2: ++ priv->InitialGain = 4; // m78dBm; ++ break; ++ default: ++ priv->InitialGain = 5; // m74dBm; ++ break; ++ } ++ } ++ InitialGainStep = 7; ++ if(priv->InitialGain > 7) ++ priv->InitialGain = 5; ++ LowestGainStage = 4; ++ } else { ++ if (priv->InitialGain == 0 ) //autoDIG ++ { // Advised from SD3 DZ, by Bruce, 2007-06-05. ++ priv->InitialGain = 4; // In 87B, m74dBm means State 4 (m82dBm) ++ } ++ if(priv->card_8187_Bversion != VERSION_8187B_B) ++ { // Advised from SD3 DZ, by Bruce, 2007-06-05. ++ OfdmFA1 = 0x20; ++ } ++ InitialGainStep = 8; ++ LowestGainStage = priv->RegBModeGainStage; // Lowest gain stage. ++ } ++ ++ if (OFDMFalseAlarm > OfdmFA1) ++ { ++ if (OFDMFalseAlarm > OfdmFA2) ++ { ++ priv->DIG_NumberFallbackVote++; ++ if (priv->DIG_NumberFallbackVote >1) ++ { ++ //serious OFDM False Alarm, need fallback ++ // By Bruce, 2007-03-29. ++ // if (pHalData->InitialGain < 7) // In 87B, m66dBm means State 7 (m74dBm) ++ if (priv->InitialGain < InitialGainStep) ++ { ++ priv->InitialGain = (priv->InitialGain + 1); ++ //printk("DIG**********OFDM False Alarm: %#X, OfdmFA1: %#X, OfdmFA2: %#X\n", OFDMFalseAlarm, OfdmFA1, OfdmFA2); ++ //printk("DIG+++++++ fallback OFDM:%d \n", priv->InitialGain); ++ UpdateInitialGain(dev); // 2005.01.06, by rcnjko. ++ } ++ priv->DIG_NumberFallbackVote = 0; ++ priv->DIG_NumberUpgradeVote=0; ++ } ++ } ++ else ++ { ++ if (priv->DIG_NumberFallbackVote) ++ priv->DIG_NumberFallbackVote--; ++ } ++ priv->DIG_NumberUpgradeVote=0; ++ } ++ else //OFDM False Alarm < 0x15 ++ { ++ if (priv->DIG_NumberFallbackVote) ++ priv->DIG_NumberFallbackVote--; ++ priv->DIG_NumberUpgradeVote++; ++ ++ if (priv->DIG_NumberUpgradeVote>9) ++ { ++ if (priv->InitialGain > LowestGainStage) // In 87B, m78dBm means State 4 (m864dBm) ++ { ++ priv->InitialGain = (priv->InitialGain - 1); ++ //printk("DIG**********OFDM False Alarm: %#X, OfdmFA1: %#X, OfdmFA2: %#X\n", OFDMFalseAlarm, OfdmFA1, OfdmFA2); ++ //printk("DIG--------- Upgrade OFDM:%d \n", priv->InitialGain); ++ UpdateInitialGain(dev); // 2005.01.06, by rcnjko. ++ } ++ priv->DIG_NumberFallbackVote = 0; ++ priv->DIG_NumberUpgradeVote=0; ++ } ++ } ++ ++// printk("DIG+++++++ OFDM:%d\n", priv->InitialGain); ++// printk("<--------- DIG_Zebra()\n"); ++} ++ ++// ++// Description: ++// Dispatch DIG implementation according to RF. ++// ++void DynamicInitGain(struct net_device *dev) ++{ ++ struct r8180_priv *priv = (struct r8180_priv *)ieee80211_priv(dev); ++ ++ switch(priv->rf_chip) ++ { ++ case RF_ZEBRA: ++ case RF_ZEBRA2: // [AnnieWorkaround] For Zebra2, 2005-08-01. ++ //case RF_ZEBRA4: ++ DIG_Zebra(dev); ++ break; ++ ++ default: ++ printk("DynamicInitGain(): unknown RFChipID(%d) !!!\n", priv->rf_chip); ++ break; ++ } ++} ++ ++// By Bruce, 2007-03-29. ++// ++// Description: ++// Dispatch CCK Power Detection implementation according to RF. ++// ++void DynamicCCKThreshold(struct net_device *dev) ++{ ++ struct r8180_priv *priv = (struct r8180_priv *)ieee80211_priv(dev); ++ u16 CCK_Up_Th; ++ u16 CCK_Lw_Th; ++ u16 CCKFalseAlarm; ++ ++ printk("=====>DynamicCCKThreshold()\n"); ++ ++ CCK_Up_Th = priv->CCKUpperTh; ++ CCK_Lw_Th = priv->CCKLowerTh; ++ CCKFalseAlarm = (u16)((priv->FalseAlarmRegValue & 0x0000ffff) >> 8); // We only care about the higher byte. ++ printk("DynamicCCKThreshold(): CCK Upper Threshold: 0x%02X, Lower Threshold: 0x%02X, CCKFalseAlarmHighByte: 0x%02X\n", CCK_Up_Th, CCK_Lw_Th, CCKFalseAlarm); ++ ++ if(priv->StageCCKTh < 3 && CCKFalseAlarm >= CCK_Up_Th) ++ { ++ priv->StageCCKTh ++; ++ UpdateCCKThreshold(dev); ++ } ++ else if(priv->StageCCKTh > 0 && CCKFalseAlarm <= CCK_Lw_Th) ++ { ++ priv->StageCCKTh --; ++ UpdateCCKThreshold(dev); ++ } ++ ++ printk("<=====DynamicCCKThreshold()\n"); ++} ++ ++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,20)) ++void rtl8180_hw_dig_wq (struct work_struct *work) ++{ ++ struct delayed_work *dwork = container_of(work,struct delayed_work,work); ++ struct ieee80211_device *ieee = container_of(dwork,struct ieee80211_device,hw_dig_wq); ++ struct net_device *dev = ieee->dev; ++#else ++void rtl8180_hw_dig_wq(struct net_device *dev) ++{ ++ // struct r8180_priv *priv = ieee80211_priv(dev); ++#endif ++ struct r8180_priv *priv = ieee80211_priv(dev); ++ ++ // Read CCK and OFDM False Alarm. ++ if(priv->card_8187_Bversion == VERSION_8187B_B) { ++ // Read only 1 byte because of HW bug. This is a temporal modification. Joseph ++ // Modify by Isaiah 2006-06-27 ++ priv->FalseAlarmRegValue = (u32)read_nic_byte(dev, (OFDM_FALSE_ALARM+1)); ++ } else { ++ priv->FalseAlarmRegValue = read_nic_dword(dev, CCK_FALSE_ALARM); ++ } ++ ++ // Adjust Initial Gain dynamically. ++ if(priv->bDigMechanism) { ++ DynamicInitGain(dev); ++ } ++ ++ // ++ // Move from DynamicInitGain to be independent of the OFDM DIG mechanism, by Bruce, 2007-06-01. ++ // ++ if(priv->card_8187 == NIC_8187B) { ++ // By Bruce, 2007-03-29. ++ // Dynamically update CCK Power Detection Threshold. ++ if(priv->bCCKThMechanism) ++ { ++ DynamicCCKThreshold(dev); ++ } ++ } ++} ++ ++void SetTxPowerLevel8187(struct net_device *dev, short chan) ++{ ++ struct r8180_priv *priv = ieee80211_priv(dev); ++ ++ switch(priv->rf_chip) ++ { ++ case RF_ZEBRA: ++ rtl8225_SetTXPowerLevel(dev,chan); ++ break; ++ ++ case RF_ZEBRA2: ++ //case RF_ZEBRA4: ++ rtl8225z2_SetTXPowerLevel(dev,chan); ++ break; ++ } ++} ++ ++// ++// Description: ++// Check if input power signal strength exceeds maximum input power threshold ++// of current HW. ++// If yes, we set our HW to high input power state: ++// RX: always force TR switch to SW Tx mode to reduce input power. ++// TX: turn off smaller Tx output power (see RtUsbCheckForHang). ++// ++// If no, we restore our HW to normal input power state: ++/// RX: restore TR switch to HW controled mode. ++// TX: restore TX output power (see RtUsbCheckForHang). ++// ++// TODO: ++// 1. Tx power control shall not be done in Platform-dependent timer (e.g. RtUsbCheckForHang). ++// 2. Allow these threshold adjustable by RF SD. ++// ++void DoRxHighPower(struct net_device *dev) ++{ ++ struct r8180_priv *priv = ieee80211_priv(dev); ++ TR_SWITCH_STATE TrSwState; ++ u16 HiPwrUpperTh = 0; ++ u16 HiPwrLowerTh = 0; ++ u16 RSSIHiPwrUpperTh = 0; ++ u16 RSSIHiPwrLowerTh = 0; ++ ++ //87S remove TrSwitch mechanism ++ if((priv->card_8187 == NIC_8187B)||(priv->card_8187 == NIC_8187)) { ++ ++ //printk("----> DoRxHighPower()\n"); ++ ++ // ++ // Get current TR switch setting. ++ // ++ //Adapter->HalFunc.GetHwRegHandler(Adapter, HW_VAR_TR_SWITCH, (pu1Byte)(&TrSwState)); ++ TrSwState = priv->TrSwitchState; ++ ++ // ++ // Determine threshold according to RF type. ++ // ++ switch(priv->rf_chip) ++ { ++ case RF_ZEBRA: ++ HiPwrUpperTh = Z1_HIPWR_UPPER_TH; ++ HiPwrLowerTh = Z1_HIPWR_LOWER_TH; ++ printk("DoRxHighPower(): RF_ZEBRA, Upper Threshold: %d LOWER Threshold: %d\n", ++ HiPwrUpperTh, HiPwrLowerTh); ++ break; ++ ++ case RF_ZEBRA2: ++ if((priv->card_8187 == NIC_8187)) { ++ HiPwrUpperTh = Z2_HIPWR_UPPER_TH; ++ HiPwrLowerTh = Z2_HIPWR_LOWER_TH; ++ } else { ++ // By Bruce, 2007-04-11. ++ // HiPwrUpperTh = Z2_HIPWR_UPPER_TH; ++ // HiPwrLowerTh = Z2_HIPWR_LOWER_TH; ++ ++ HiPwrUpperTh = priv->Z2HiPwrUpperTh; ++ HiPwrLowerTh = priv->Z2HiPwrLowerTh; ++ HiPwrUpperTh = HiPwrUpperTh * 10; ++ HiPwrLowerTh = HiPwrLowerTh * 10; ++ ++ RSSIHiPwrUpperTh = priv->Z2RSSIHiPwrUpperTh; ++ RSSIHiPwrLowerTh = priv->Z2RSSIHiPwrLowerTh; ++ //printk("DoRxHighPower(): RF_ZEBRA2, Upper Threshold: %d LOWER Threshold: %d, RSSI Upper Th: %d, RSSI Lower Th: %d\n",HiPwrUpperTh, HiPwrLowerTh, RSSIHiPwrUpperTh, RSSIHiPwrLowerTh); ++ } ++ break; ++ ++ default: ++ printk("DoRxHighPower(): Unknown RFChipID(%d), UndecoratedSmoothedSS(%d), TrSwState(%d)!!!\n", ++ priv->rf_chip, priv->UndecoratedSmoothedSS, TrSwState); ++ return; ++ break; ++ } ++ ++ /*printk(">>>>>>>>>>Set TR switch to software control, UndecoratedSmoothedSS:%d, CurCCKRSSI = %d\n",\ ++ priv->UndecoratedSmoothedSS, priv->CurCCKRSSI); ++ */ ++ if((priv->card_8187 == NIC_8187)) { ++ // ++ // Perform Rx part High Power Mechanism by UndecoratedSmoothedSS. ++ // ++ if (priv->UndecoratedSmoothedSS > HiPwrUpperTh) ++ { // High input power state. ++ if( priv->TrSwitchState == TR_HW_CONTROLLED ) ++ { ++ /* printk(">>>>>>>>>>Set TR switch to software control, UndecoratedSmoothedSS:%d \n", \ ++ priv->UndecoratedSmoothedSS); ++ // printk(">>>>>>>>>> TR_SW_TX\n"); ++ */ ++ write_nic_byte(dev, RFPinsSelect, ++ (u8)(priv->wMacRegRfPinsSelect | TR_SW_MASK_8187 )); ++ write_nic_byte(dev, RFPinsOutput, ++ (u8)((priv->wMacRegRfPinsOutput&(~TR_SW_MASK_8187))|TR_SW_MASK_TX_8187)); ++ priv->TrSwitchState = TR_SW_TX; ++ priv->bToUpdateTxPwr = true; ++ } ++ } ++ else if (priv->UndecoratedSmoothedSS < HiPwrLowerTh) ++ { // Normal input power state. ++ if( priv->TrSwitchState == TR_SW_TX) ++ { ++ /* printk("<<<<<<<<<<<Set TR switch to hardware control UndecoratedSmoothedSS:%d \n", \ ++ priv->UndecoratedSmoothedSS); ++ // printk("<<<<<<<<<< TR_HW_CONTROLLED\n"); ++ */ ++ write_nic_byte(dev, RFPinsOutput, (u8)(priv->wMacRegRfPinsOutput)); ++ write_nic_byte(dev, RFPinsSelect, (u8)(priv->wMacRegRfPinsSelect)); ++ priv->TrSwitchState = TR_HW_CONTROLLED; ++ priv->bToUpdateTxPwr = true; ++ } ++ } ++ }else { ++ /*printk("=====>TrSwState = %s\n", (TrSwState==TR_HW_CONTROLLED)?"TR_HW_CONTROLLED":"TR_SW_TX"); ++ //printk("UndecoratedSmoothedSS:%d, CurCCKRSSI = %d\n",priv->UndecoratedSmoothedSS, priv->CurCCKRSSI); */ ++ // Asked by SD3 DZ, by Bruce, 2007-04-12. ++ if(TrSwState == TR_HW_CONTROLLED) ++ { ++ if((priv->UndecoratedSmoothedSS > HiPwrUpperTh) || ++ (priv->bCurCCKPkt && (priv->CurCCKRSSI > RSSIHiPwrUpperTh))) ++ { ++ //printk("===============================> high power!\n"); ++ write_nic_byte(dev, RFPinsSelect, (u8)(priv->wMacRegRfPinsSelect|TR_SW_MASK_8187 )); ++ write_nic_byte(dev, RFPinsOutput, ++ (u8)((priv->wMacRegRfPinsOutput&(~TR_SW_MASK_8187))|TR_SW_MASK_TX_8187)); ++ priv->TrSwitchState = TR_SW_TX; ++ priv->bToUpdateTxPwr = true; ++ } ++ } ++ else ++ { ++ if((priv->UndecoratedSmoothedSS < HiPwrLowerTh) && ++ (!priv->bCurCCKPkt || priv->CurCCKRSSI < RSSIHiPwrLowerTh)) ++ { ++ write_nic_byte(dev, RFPinsOutput, (u8)(priv->wMacRegRfPinsOutput)); ++ write_nic_byte(dev, RFPinsSelect, (u8)(priv->wMacRegRfPinsSelect)); ++ priv->TrSwitchState = TR_HW_CONTROLLED; ++ priv->bToUpdateTxPwr = true; ++ } ++ } ++ //printk("<=======TrSwState = %s\n", (TrSwState==TR_HW_CONTROLLED)?"TR_HW_CONTROLLED":"TR_SW_TX"); ++ } ++ //printk("<---- DoRxHighPower()\n"); ++ } ++} ++ ++ ++// ++// Description: ++// Callback function of UpdateTxPowerWorkItem. ++// Because of some event happend, e.g. CCX TPC, High Power Mechanism, ++// We update Tx power of current channel again. ++// ++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,20)) ++void rtl8180_tx_pw_wq (struct work_struct *work) ++{ ++ struct delayed_work *dwork = container_of(work,struct delayed_work,work); ++ struct ieee80211_device *ieee = container_of(dwork,struct ieee80211_device,tx_pw_wq); ++ struct net_device *dev = ieee->dev; ++#else ++void rtl8180_tx_pw_wq(struct net_device *dev) ++{ ++ // struct r8180_priv *priv = ieee80211_priv(dev); ++#endif ++ ++ struct r8180_priv *priv = ieee80211_priv(dev); ++ ++ //printk("----> UpdateTxPowerWorkItemCallback()\n"); ++ ++ if(priv->bToUpdateTxPwr) ++ { ++ //printk("DoTxHighPower(): schedule UpdateTxPowerWorkItem......\n"); ++ priv->bToUpdateTxPwr = false; ++ SetTxPowerLevel8187(dev, priv->chan); ++ } ++ ++ DoRxHighPower(dev); ++ //printk("<---- UpdateTxPowerWorkItemCallback()\n"); ++} ++ ++// ++// Description: ++// Return TRUE if we shall perform High Power Mecahnism, FALSE otherwise. ++// ++bool CheckHighPower(struct net_device *dev) ++{ ++ struct r8180_priv *priv = ieee80211_priv(dev); ++ struct ieee80211_device *ieee = priv->ieee80211; ++ ++ if(!priv->bRegHighPowerMechanism) ++ { ++ return false; ++ } ++ ++ if((ieee->state == IEEE80211_LINKED_SCANNING)||(ieee->state == IEEE80211_MESH_SCANNING)) ++ { ++ return false; ++ } ++ ++ return true; ++} ++ ++#ifdef SW_ANTE_DIVERSITY ++ ++#define ANTENNA_DIVERSITY_TIMER_PERIOD 1000 // 1000 m ++ ++void ++SwAntennaDiversityRxOk8185( ++ struct net_device *dev, ++ u8 SignalStrength ++ ) ++{ ++ struct r8180_priv *priv = (struct r8180_priv *)ieee80211_priv(dev); ++ ++ //printk("+SwAntennaDiversityRxOk8185: RxSs: %d\n", SignalStrength); ++ ++ priv->AdRxOkCnt++; ++ ++ if( priv->AdRxSignalStrength != -1) ++ { ++ priv->AdRxSignalStrength = ((priv->AdRxSignalStrength*7) + (SignalStrength*3)) / 10; ++ } ++ else ++ { // Initialization case. ++ priv->AdRxSignalStrength = SignalStrength; ++ } ++ ++ //printk("====>pkt rcvd by %d\n", priv->LastRxPktAntenna); ++ if( priv->LastRxPktAntenna ) //Main antenna. ++ priv->AdMainAntennaRxOkCnt++; ++ else // Aux antenna. ++ priv->AdAuxAntennaRxOkCnt++; ++ //printk("-SwAntennaDiversityRxOk8185: AdRxOkCnt: %d AdRxSignalStrength: %d\n", priv->AdRxOkCnt, priv->AdRxSignalStrength); ++} ++ ++// ++// Description: Change Antenna Switch. ++// ++bool ++SetAntenna8185( ++ struct net_device *dev, ++ u8 u1bAntennaIndex ++ ) ++{ ++ struct r8180_priv *priv = (struct r8180_priv *)ieee80211_priv(dev); ++ bool bAntennaSwitched = false; ++ ++// printk("+SetAntenna8185(): Antenna is switching to: %d \n", u1bAntennaIndex); ++ ++ switch(u1bAntennaIndex) ++ { ++ case 0://main antenna ++ switch(priv->rf_chip) ++ { ++ case RF_ZEBRA: ++ case RF_ZEBRA2: ++ //case RF_ZEBRA4: ++ // Tx Antenna. ++ write_nic_byte(dev, ANTSEL, 0x03); // Config TX antenna. ++ ++ //PlatformEFIOWrite4Byte(Adapter, BBAddr, 0x01009b90); // Config CCK RX antenna. ++ //PlatformEFIOWrite4Byte(Adapter, BBAddr, 0x5c8D); // Config OFDM RX antenna. ++ ++ // Rx CCK . ++ write_nic_byte(dev, 0x7f, ((0x01009b90 & 0xff000000) >> 24)); ++ write_nic_byte(dev, 0x7e, ((0x01009b90 & 0x00ff0000) >> 16)); ++ write_nic_byte(dev, 0x7d, ((0x01009b90 & 0x0000ff00) >> 8)); ++ write_nic_byte(dev, 0x7c, ((0x01009b90 & 0x000000ff) >> 0)); ++ ++ // Rx OFDM. ++ write_nic_byte(dev, 0x7f, ((0x00005c8D & 0xff000000) >> 24)); ++ write_nic_byte(dev, 0x7e, ((0x00005c8D & 0x00ff0000) >> 16)); ++ write_nic_byte(dev, 0x7d, ((0x00005c8D & 0x0000ff00) >> 8)); ++ write_nic_byte(dev, 0x7c, ((0x00005c8D & 0x000000ff) >> 0)); ++ ++ bAntennaSwitched = true; ++ break; ++ ++ default: ++ printk("SetAntenna8185: unkown RFChipID(%d)\n", priv->rf_chip); ++ break; ++ } ++ break; ++ ++ case 1: ++ switch(priv->rf_chip) ++ { ++ case RF_ZEBRA: ++ case RF_ZEBRA2: ++ //case RF_ZEBRA4: ++ // Tx Antenna. ++ write_nic_byte(dev, ANTSEL, 0x00); // Config TX antenna. ++ ++ //PlatformEFIOWrite4Byte(Adapter, BBAddr, 0x0100bb90); // Config CCK RX antenna. ++ //PlatformEFIOWrite4Byte(Adapter, BBAddr, 0x548D); // Config OFDM RX antenna. ++ ++ // Rx CCK. ++ write_nic_byte(dev, 0x7f, ((0x0100bb90 & 0xff000000) >> 24)); ++ write_nic_byte(dev, 0x7e, ((0x0100bb90 & 0x00ff0000) >> 16)); ++ write_nic_byte(dev, 0x7d, ((0x0100bb90 & 0x0000ff00) >> 8)); ++ write_nic_byte(dev, 0x7c, ((0x0100bb90 & 0x000000ff) >> 0)); ++ ++ // Rx OFDM. ++ write_nic_byte(dev, 0x7f, ((0x0000548D & 0xff000000) >> 24)); ++ write_nic_byte(dev, 0x7e, ((0x0000548D & 0x00ff0000) >> 16)); ++ write_nic_byte(dev, 0x7d, ((0x0000548D & 0x0000ff00) >> 8)); ++ write_nic_byte(dev, 0x7c, ((0x0000548D & 0x000000ff) >> 0)); ++ ++ bAntennaSwitched = true; ++ break; ++ ++ default: ++ printk("SetAntenna8185: unkown RFChipID(%d)\n", priv->rf_chip); ++ break; ++ } ++ break; ++ ++ default: ++ printk("SetAntenna8185: unkown u1bAntennaIndex(%d)\n", u1bAntennaIndex); ++ break; ++ } ++ ++ if(bAntennaSwitched) ++ { ++ priv->CurrAntennaIndex = u1bAntennaIndex; ++ } ++ ++// printk("-SetAntenna8185(): return (%#X)\n", bAntennaSwitched); ++ ++ return bAntennaSwitched; ++} ++ ++// ++// Description: Toggle Antenna switch. ++// ++bool SwitchAntenna(struct net_device *dev) ++{ ++ struct r8180_priv *priv = (struct r8180_priv *)ieee80211_priv(dev); ++ ++ bool bResult = false; ++ ++ if(priv->CurrAntennaIndex == 0) ++ { ++ bResult = SetAntenna8185(dev, 1); ++ if(priv->ieee80211->state == IEEE80211_LINKED) ++ printk("Switching to Aux antenna 1 \n"); ++ } ++ else ++ { ++ bResult = SetAntenna8185(dev, 0); ++ if(priv->ieee80211->state == IEEE80211_LINKED) ++ printk("Switching to Main antenna 0 \n"); ++ } ++ ++ return bResult; ++} ++ ++// ++// Description: ++// Engine of SW Antenna Diversity mechanism. ++// Since 8187 has no Tx part information, ++// this implementation is only dependend on Rx part information. ++// ++// 2006.04.17, by rcnjko. ++// ++void SwAntennaDiversity(struct net_device *dev) ++{ ++ struct r8180_priv *priv = (struct r8180_priv *)ieee80211_priv(dev); ++ //bool bSwCheckSS=false; ++ bool bSwCheckSS=true;//open the SignalStrength check if not switched by rx ok pkt. ++ ++// printk("+SwAntennaDiversity(): CurrAntennaIndex: %d\n", priv->CurrAntennaIndex); ++ ++//by amy 080312 ++ if(bSwCheckSS){ ++ priv->AdTickCount++; ++ ++ //printk("(1) AdTickCount: %d, AdCheckPeriod: %d\n", priv->AdTickCount, priv->AdCheckPeriod); ++ //printk("(2) AdRxSignalStrength: %ld, AdRxSsThreshold: %ld\n", priv->AdRxSignalStrength, priv->AdRxSsThreshold); ++ } ++// priv->AdTickCount++;//-by amy 080312 ++ ++ // Case 1. No Link. ++ if(priv->ieee80211->state != IEEE80211_LINKED){ ++ //printk("SwAntennaDiversity(): Case 1. No Link.\n"); ++ ++ priv->bAdSwitchedChecking = false; ++ // I switch antenna here to prevent any one of antenna is broken before link established, 2006.04.18, by rcnjko.. ++ SwitchAntenna(dev); ++ } ++ // Case 2. Linked but no packet received. ++ else if(priv->AdRxOkCnt == 0){ ++ printk("SwAntennaDiversity(): Case 2. Linked but no packet received.\n"); ++ ++ priv->bAdSwitchedChecking = false; ++ SwitchAntenna(dev); ++ } ++ // Case 3. Evaluate last antenna switch action in case4. and undo it if necessary. ++ else if(priv->bAdSwitchedChecking == true){ ++ //printk("SwAntennaDiversity(): Case 3. Evaluate last antenna switch action.\n"); ++ ++ priv->bAdSwitchedChecking = false; ++ ++ // Adjust Rx signal strength threashold. ++ priv->AdRxSsThreshold = (priv->AdRxSignalStrength + priv->AdRxSsBeforeSwitched) / 2; ++ ++ priv->AdRxSsThreshold = (priv->AdRxSsThreshold > priv->AdMaxRxSsThreshold) ? ++ priv->AdMaxRxSsThreshold: priv->AdRxSsThreshold; ++ if(priv->AdRxSignalStrength < priv->AdRxSsBeforeSwitched){ ++ // Rx signal strength is not improved after we swtiched antenna. => Swich back. ++ printk("SwAntennaDiversity(): Rx Signal Strength is not improved, CurrRxSs: %ld, LastRxSs: %ld\n", priv->AdRxSignalStrength, priv->AdRxSsBeforeSwitched); ++ ++ //by amy 080312 ++ // Increase Antenna Diversity checking period due to bad decision. ++ priv->AdCheckPeriod *= 2; ++ //by amy 080312 ++ // ++ // Increase Antenna Diversity checking period. ++ if(priv->AdCheckPeriod > priv->AdMaxCheckPeriod) ++ priv->AdCheckPeriod = priv->AdMaxCheckPeriod; ++ ++ // Wrong deceision => switch back. ++ SwitchAntenna(dev); ++ }else{ // Rx Signal Strength is improved. ++ printk("SwAntennaDiversity(): Rx Signal Strength is improved, CurrRxSs: %ld, LastRxSs: %ld\n", priv->AdRxSignalStrength, priv->AdRxSsBeforeSwitched); ++ ++ // Reset Antenna Diversity checking period to its min value. ++ priv->AdCheckPeriod = priv->AdMinCheckPeriod; ++ } ++ ++ //printk("SwAntennaDiversity(): AdRxSsThreshold: %ld, AdCheckPeriod: %d\n", ++ // priv->AdRxSsThreshold, priv->AdCheckPeriod); ++ } ++ // Case 4. Evaluate if we shall switch antenna now. ++ // Cause Table Speed is very fast in TRC Dell Lab, we check it every time. ++ else// if(priv->AdTickCount >= priv->AdCheckPeriod)//-by amy 080312 ++ { ++ //printk("SwAntennaDiversity(): Case 4. Evaluate if we shall switch antenna now.\n"); ++ ++ priv->AdTickCount = 0; ++ ++ // ++ // <Roger_Notes> We evaluate RxOk counts for each antenna first and than ++ // evaluate signal strength. ++ // The following operation can overcome the disability of CCA on both two antennas ++ // When signal strength was extremely low or high. ++ // 2008.01.30. ++ // ++ ++ // ++ // Evaluate RxOk count from each antenna if we shall switch default antenna now. ++ // Added by Roger, 2008.02.21. ++ ++ //{by amy 080312 ++ if((priv->AdMainAntennaRxOkCnt < priv->AdAuxAntennaRxOkCnt) && (priv->CurrAntennaIndex == 0)){ ++ // We set Main antenna as default but RxOk count was less than Aux ones. ++ ++ printk("SwAntennaDiversity(): Main antenna %d RxOK is poor, AdMainAntennaRxOkCnt: %d, AdAuxAntennaRxOkCnt: %d\n",priv->CurrAntennaIndex, priv->AdMainAntennaRxOkCnt, priv->AdAuxAntennaRxOkCnt); ++ ++ // Switch to Aux antenna. ++ SwitchAntenna(dev); ++ priv->bHWAdSwitched = true; ++ }else if((priv->AdAuxAntennaRxOkCnt < priv->AdMainAntennaRxOkCnt) && (priv->CurrAntennaIndex == 1)){ ++ // We set Aux antenna as default but RxOk count was less than Main ones. ++ ++ printk("SwAntennaDiversity(): Aux antenna %d RxOK is poor, AdMainAntennaRxOkCnt: %d, AdAuxAntennaRxOkCnt: %d\n",priv->CurrAntennaIndex, priv->AdMainAntennaRxOkCnt, priv->AdAuxAntennaRxOkCnt); ++ ++ // Switch to Main antenna. ++ SwitchAntenna(dev); ++ priv->bHWAdSwitched = true; ++ }else{// Default antenna is better. ++ ++ printk("SwAntennaDiversity(): Current Antenna %d is better., AdMainAntennaRxOkCnt: %d, AdAuxAntennaRxOkCnt: %d\n",priv->CurrAntennaIndex, priv->AdMainAntennaRxOkCnt, priv->AdAuxAntennaRxOkCnt); ++ ++ // Still need to check current signal strength. ++ priv->bHWAdSwitched = false; ++ } ++ // ++ // <Roger_Notes> We evaluate Rx signal strength ONLY when default antenna ++ // didn't changed by HW evaluation. ++ // 2008.02.27. ++ // ++ // [TRC Dell Lab] SignalStrength is inaccuracy. Isaiah 2008-03-05 ++ // For example, Throughput of aux is better than main antenna(about 10M v.s 2M), ++ // but AdRxSignalStrength is less than main. ++ // Our guess is that main antenna have lower throughput and get many change ++ // to receive more CCK packets(ex.Beacon) which have stronger SignalStrength. ++ // ++ if( (!priv->bHWAdSwitched) && (bSwCheckSS)){ ++ //by amy 080312} ++ ++ // Evaluate Rx signal strength if we shall switch antenna now. ++ if(priv->AdRxSignalStrength < priv->AdRxSsThreshold){ ++ // Rx signal strength is weak => Switch Antenna. ++ printk("SwAntennaDiversity(): Rx Signal Strength is weak, CurrRxSs: %ld, RxSsThreshold: %ld\n", priv->AdRxSignalStrength, priv->AdRxSsThreshold); ++ ++ priv->AdRxSsBeforeSwitched = priv->AdRxSignalStrength; ++ priv->bAdSwitchedChecking = true; ++ ++ SwitchAntenna(dev); ++ }else{ // Rx signal strength is OK. ++ printk("SwAntennaDiversity(): Rx Signal Strength is OK, CurrRxSs: %ld, RxSsThreshold: %ld\n", priv->AdRxSignalStrength, priv->AdRxSsThreshold); ++ ++ priv->bAdSwitchedChecking = false; ++ // Increase Rx signal strength threashold if necessary. ++ if( (priv->AdRxSignalStrength > (priv->AdRxSsThreshold + 10)) && // Signal is much stronger than current threshold ++ priv->AdRxSsThreshold <= priv->AdMaxRxSsThreshold) // Current threhold is not yet reach upper limit. ++ { ++ priv->AdRxSsThreshold = (priv->AdRxSsThreshold + priv->AdRxSignalStrength) / 2; ++ priv->AdRxSsThreshold = (priv->AdRxSsThreshold > priv->AdMaxRxSsThreshold) ? ++ priv->AdMaxRxSsThreshold: priv->AdRxSsThreshold;//+by amy 080312 ++ } ++ ++ // Reduce Antenna Diversity checking period if possible. ++ if( priv->AdCheckPeriod > priv->AdMinCheckPeriod ) ++ { ++ priv->AdCheckPeriod /= 2; ++ } ++ } ++ } ++ } ++//by amy 080312 ++ // Reset antenna diversity Rx related statistics. ++ priv->AdRxOkCnt = 0; ++ priv->AdMainAntennaRxOkCnt = 0; ++ priv->AdAuxAntennaRxOkCnt = 0; ++//by amy 080312 ++ ++// priv->AdRxOkCnt = 0;//-by amy 080312 ++ ++ //printk("-SwAntennaDiversity()\n"); ++} ++ ++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,20)) ++void SwAntennaWorkItemCallback(struct work_struct *work) ++{ ++ struct ieee80211_device *ieee = container_of(work, struct ieee80211_device, SwAntennaWorkItem.work); ++ struct net_device *dev = ieee->dev; ++#else ++void SwAntennaWorkItemCallback(struct net_device *dev) ++{ ++#endif ++ //printk("==>%s \n", __func__); ++ SwAntennaDiversity(dev); ++} ++ ++// ++// Description: Timer callback function of SW Antenna Diversity. ++// ++void SwAntennaDiversityTimerCallback(struct net_device *dev) ++{ ++ struct r8180_priv *priv = (struct r8180_priv *)ieee80211_priv(dev); ++ RT_RF_POWER_STATE rtState; ++ ++ //printk("+SwAntennaDiversityTimerCallback()\n"); ++ ++ // ++ // We do NOT need to switch antenna while RF is off. ++ // 2007.05.09, added by Roger. ++ // ++ rtState = priv->eRFPowerState; ++ do{ ++ if (rtState == eRfOff){ ++// printk("SwAntennaDiversityTimer - RF is OFF.\n"); ++ break; ++ }else if (rtState == eRfSleep){ ++ // Don't access BB/RF under Disable PLL situation. ++ //RT_TRACE((COMP_RF|COMP_ANTENNA), DBG_LOUD, ("SwAntennaDiversityTimerCallback(): RF is Sleep => skip it\n")); ++ break; ++ } ++ ++ queue_work(priv->ieee80211->wq,(void *)&priv->ieee80211->SwAntennaWorkItem); ++ ++ }while(false); ++ ++ if(priv->up){ ++ //priv->SwAntennaDiversityTimer.expires = jiffies + MSECS(ANTENNA_DIVERSITY_TIMER_PERIOD); ++ //add_timer(&priv->SwAntennaDiversityTimer); ++ mod_timer(&priv->SwAntennaDiversityTimer, jiffies + MSECS(ANTENNA_DIVERSITY_TIMER_PERIOD)); ++ } ++ ++} ++#endif ++ ++ ++ +diff -Nur linux-2.6.33/drivers/net/wireless/rtl8187b/r8180_dm.h linux-lemote/drivers/net/wireless/rtl8187b/r8180_dm.h +--- linux-2.6.33/drivers/net/wireless/rtl8187b/r8180_dm.h 1970-01-01 01:00:00.000000000 +0100 ++++ linux-lemote/drivers/net/wireless/rtl8187b/r8180_dm.h 2010-03-06 16:43:22.000000000 +0100 +@@ -0,0 +1,38 @@ ++/* ++ Hardware dynamic mechanism for RTL8187B. ++Notes: ++ This file is ported from RTL8187B Windows driver ++*/ ++ ++#ifndef R8180_DM_H ++#define R8180_DM_H ++ ++#include "r8187.h" ++ ++bool CheckDig(struct net_device *dev); ++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,20)) ++void rtl8180_hw_dig_wq (struct work_struct *work); ++#else ++void rtl8180_hw_dig_wq(struct net_device *dev); ++#endif ++ ++bool CheckHighPower(struct net_device *dev); ++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,20)) ++void rtl8180_tx_pw_wq (struct work_struct *work); ++#else ++void rtl8180_tx_pw_wq(struct net_device *dev); ++#endif ++ ++//by lzm for antenna ++#ifdef SW_ANTE_DIVERSITY ++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,20)) ++void SwAntennaWorkItemCallback(struct work_struct *work); ++#else ++void SwAntennaWorkItemCallback(struct net_device *dev); ++#endif ++void SwAntennaDiversityRxOk8185(struct net_device *dev, u8 SignalStrength); ++void SwAntennaDiversityTimerCallback(struct net_device *dev); ++#endif ++//by lzm for antenna ++ ++#endif //R8180_PM_H +diff -Nur linux-2.6.33/drivers/net/wireless/rtl8187b/r8180_hw.h linux-lemote/drivers/net/wireless/rtl8187b/r8180_hw.h +--- linux-2.6.33/drivers/net/wireless/rtl8187b/r8180_hw.h 1970-01-01 01:00:00.000000000 +0100 ++++ linux-lemote/drivers/net/wireless/rtl8187b/r8180_hw.h 2010-03-06 16:43:22.000000000 +0100 +@@ -0,0 +1,788 @@ ++/* ++ This is part of rtl8187 OpenSource driver. ++ Copyright (C) Andrea Merello 2004-2005 <andreamrl@tiscali.it> ++ Released under the terms of GPL (General Public Licence) ++ ++ Parts of this driver are based on the GPL part of the ++ official Realtek driver. ++ Parts of this driver are based on the rtl8180 driver skeleton ++ from Patric Schenke & Andres Salomon. ++ Parts of this driver are based on the Intel Pro Wireless ++ 2100 GPL driver. ++ ++ We want to tanks the Authors of those projects ++ and the Ndiswrapper project Authors. ++*/ ++ ++/* Mariusz Matuszek added full registers definition with Realtek's name */ ++ ++/* this file contains register definitions for the rtl8187 MAC controller */ ++#ifndef R8180_HW ++#define R8180_HW ++ ++typedef enum _RF_TYPE_8187{ ++ RF_TYPE_MIN, ++ RF_ZEBRA = 5, ++ RF_ZEBRA2, // added by Annie, 2005-08-01. ++ RF_TYPE_MAX, ++}RF_TYPE_8187,*PRF_TYPE_8187; ++ ++typedef enum _VERSION_8187{ ++ // RTL8187 ++ VERSION_8187_B, // B-cut ++ VERSION_8187_D, // D-cut ++ // RTL8187B ++ VERSION_8187B_B, // B-cut ++ VERSION_8187B_D, //D-cut //added 2007-9-14 ++ VERSION_8187B_E, //E-cut //added 2007-9-14 ++}VERSION_8187,*PVERSION_8187; ++ ++//by lzm for antenna ++#ifdef SW_ANTE_DIVERSITY ++#define RF_PARAM 0x19 ++#define RF_PARAM_DIGPHY_SHIFT 0 ++#define RF_PARAM_ANTBDEFAULT_SHIFT 1 ++#define EEPROM_VERSION 0x3c ++#define EEPROM_CONFIG2 0x18 ++#define EEPROM_CS_THRESHOLD 0x2F ++#define EEPROM_RF_PARAM 0x08 ++//// BIT[8-9] is for SW Antenna Diversity. Only the value EEPROM_SW_AD_ENABLE means enable, other values are diable. ++#define EEPROM_SW_AD_MASK 0x0300 ++#define EEPROM_SW_AD_ENABLE 0x0100 ++//// BIT[10-11] determine if Antenna 1 is the Default Antenna. Only the value EEPROM_DEF_ANT_1 means TRUE, other values are FALSE. ++#define EEPROM_DEF_ANT_MASK 0x0C00 ++#define EEPROM_DEF_ANT_1 0x0400 ++ ++#define RCR_EnCS1 BIT29 // enable carrier sense method 1 ++#define RCR_EnCS2 BIT30 // enable carrier sense method 2 ++#endif ++//by lzm for antenna ++ ++#define RTL8187_RF_INDEX 0x8225 ++#define RTL8187_REQT_READ 0xc0 ++#define RTL8187_REQT_WRITE 0x40 ++#define RTL8187_REQ_GET_REGS 0x05 ++#define RTL8187_REQ_SET_REGS 0x05 ++ ++ ++ ++#define MAX_TX_URB 5 ++#define MAX_RX_URB 16 ++#define RX_URB_SIZE 0x9C4 ++ ++ ++ ++ ++ ++#define BB_ANTATTEN_CHAN14 0x0c ++#define BB_ANTENNA_B 0x40 ++ ++#define BB_HOST_BANG (1<<30) ++#define BB_HOST_BANG_EN (1<<2) ++#define BB_HOST_BANG_CLK (1<<1) ++#define BB_HOST_BANG_RW (1<<3) ++#define BB_HOST_BANG_DATA 1 ++ ++#define ANAPARAM_TXDACOFF_SHIFT 27 ++#define ANAPARAM_PWR0_MASK ((1<<30)|(1<<29)|(1<<28)) ++#define ANAPARAM_PWR0_SHIFT 28 ++#define ANAPARAM_PWR1_MASK ((1<<26)|(1<<25)|(1<<24)|(1<<23)|(1<<22)|(1<<21)|(1<<20)) ++#define ANAPARAM_PWR1_SHIFT 20 ++ ++#define MAC0 0 ++#define MAC1 1 ++#define MAC2 2 ++#define MAC3 3 ++#define MAC4 4 ++#define MAC5 5 ++ ++#define RXFIFOCOUNT 0x10 ++#define TXFIFOCOUNT 0x12 ++#define BcnIntTime 0x74 ++#define TALLY_SEL 0xfc ++#define BQREQ 0x13 ++ ++#define CMD 0x37 ++#define CMD_RST_SHIFT 4 ++#define CMD_RESERVED_MASK ((1<<1) | (1<<5) | (1<<6) | (1<<7)) ++#define CMD_RX_ENABLE_SHIFT 3 ++#define CMD_TX_ENABLE_SHIFT 2 ++ ++#define EPROM_CMD 0x50 ++#define EPROM_CMD_RESERVED_MASK ((1<<5)|(1<<4)) ++#define EPROM_CMD_OPERATING_MODE_SHIFT 6 ++#define EPROM_CMD_OPERATING_MODE_MASK ((1<<7)|(1<<6)) ++#define EPROM_CMD_CONFIG 0x3 ++#define EPROM_CMD_NORMAL 0 ++#define EPROM_CMD_LOAD 1 ++#define EPROM_CMD_PROGRAM 2 ++#define EPROM_CS_SHIFT 3 ++#define EPROM_CK_SHIFT 2 ++#define EPROM_W_SHIFT 1 ++#define EPROM_R_SHIFT 0 ++#define CONFIG2_DMA_POLLING_MODE_SHIFT 3 ++#define INTA 0x3e ++#define INTA_TXOVERFLOW (1<<15) ++#define INTA_TIMEOUT (1<<14) ++#define INTA_BEACONTIMEOUT (1<<13) ++#define INTA_ATIM (1<<12) ++#define INTA_BEACONDESCERR (1<<11) ++#define INTA_BEACONDESCOK (1<<10) ++#define INTA_HIPRIORITYDESCERR (1<<9) ++#define INTA_HIPRIORITYDESCOK (1<<8) ++#define INTA_NORMPRIORITYDESCERR (1<<7) ++#define INTA_NORMPRIORITYDESCOK (1<<6) ++#define INTA_RXOVERFLOW (1<<5) ++#define INTA_RXDESCERR (1<<4) ++#define INTA_LOWPRIORITYDESCERR (1<<3) ++#define INTA_LOWPRIORITYDESCOK (1<<2) ++#define INTA_RXCRCERR (1<<1) ++#define INTA_RXOK (1) ++#define INTA_MASK 0x3c ++#define RXRING_ADDR 0xe4 // page 0 ++#define PGSELECT 0x5e ++#define PGSELECT_PG_SHIFT 0 ++#define RX_CONF 0x44 ++#define MAC_FILTER_MASK ((1<<0) | (1<<1) | (1<<2) | (1<<3) | (1<<5) | \ ++(1<<12) | (1<<18) | (1<<19) | (1<<20) | (1<<21) | (1<<22) | (1<<23)) ++#define RX_CHECK_BSSID_SHIFT 23 ++#define ACCEPT_PWR_FRAME_SHIFT 22 ++#define ACCEPT_MNG_FRAME_SHIFT 20 ++#define ACCEPT_CTL_FRAME_SHIFT 19 ++#define ACCEPT_DATA_FRAME_SHIFT 18 ++#define ACCEPT_ICVERR_FRAME_SHIFT 12 ++#define ACCEPT_CRCERR_FRAME_SHIFT 5 ++#define ACCEPT_BCAST_FRAME_SHIFT 3 ++#define ACCEPT_MCAST_FRAME_SHIFT 2 ++#define ACCEPT_ALLMAC_FRAME_SHIFT 0 ++#define ACCEPT_NICMAC_FRAME_SHIFT 1 ++#define RX_FIFO_THRESHOLD_MASK ((1<<13) | (1<<14) | (1<<15)) ++#define RX_FIFO_THRESHOLD_SHIFT 13 ++#define RX_FIFO_THRESHOLD_128 3 ++#define RX_FIFO_THRESHOLD_256 4 ++#define RX_FIFO_THRESHOLD_512 5 ++#define RX_FIFO_THRESHOLD_1024 6 ++#define RX_FIFO_THRESHOLD_NONE 7 ++#define RX_AUTORESETPHY_SHIFT 28 ++#define EPROM_TYPE_SHIFT 6 ++#define TX_CONF 0x40 ++#define TX_CONF_HEADER_AUTOICREMENT_SHIFT 30 ++#define TX_LOOPBACK_SHIFT 17 ++#define TX_LOOPBACK_MAC 1 ++#define TX_LOOPBACK_BASEBAND 2 ++#define TX_LOOPBACK_NONE 0 ++#define TX_LOOPBACK_CONTINUE 3 ++#define TX_LOOPBACK_MASK ((1<<17)|(1<<18)) ++#define TX_LRLRETRY_SHIFT 0 ++#define R8180_MAX_RETRY 255 ++#define TX_SRLRETRY_SHIFT 8 ++#define TX_NOICV_SHIFT 19 ++#define TX_NOCRC_SHIFT 16 ++#define TX_DMA_POLLING 0xd9 ++#define TX_DMA_POLLING_BEACON_SHIFT 7 ++#define TX_DMA_POLLING_HIPRIORITY_SHIFT 6 ++#define TX_DMA_POLLING_NORMPRIORITY_SHIFT 5 ++#define TX_DMA_POLLING_LOWPRIORITY_SHIFT 4 ++#define TX_DMA_STOP_BEACON_SHIFT 3 ++#define TX_DMA_STOP_HIPRIORITY_SHIFT 2 ++#define TX_DMA_STOP_NORMPRIORITY_SHIFT 1 ++#define TX_DMA_STOP_LOWPRIORITY_SHIFT 0 ++#define TX_NORMPRIORITY_RING_ADDR 0x24 ++#define TX_HIGHPRIORITY_RING_ADDR 0x28 ++#define TX_LOWPRIORITY_RING_ADDR 0x20 ++#define MAX_RX_DMA_MASK ((1<<8) | (1<<9) | (1<<10)) ++#define MAX_RX_DMA_2048 7 ++#define MAX_RX_DMA_1024 6 ++#define MAX_RX_DMA_SHIFT 10 ++#define INT_TIMEOUT 0x48 ++#define CONFIG3_CLKRUN_SHIFT 2 ++#define CONFIG3_ANAPARAM_W_SHIFT 6 ++#define ANAPARAM 0x54 ++#define BEACON_INTERVAL 0x70 ++#define BEACON_INTERVAL_MASK ((1<<0)|(1<<1)|(1<<2)|(1<<3)|(1<<4)|(1<<5)| \ ++(1<<6)|(1<<7)|(1<<8)|(1<<9)) ++#define ATIM_MASK ((1<<0)|(1<<1)|(1<<2)|(1<<3)|(1<<4)|(1<<5)|(1<<6)|(1<<7)| \ ++(1<<8)|(1<<9)) ++#define ATIM 0x72 ++#define EPROM_CS_SHIFT 3 ++#define EPROM_CK_SHIFT 2 ++#define PHY_DELAY 0x78 ++#define PHY_CONFIG 0x80 ++#define PHY_ADR 0x7c ++#define PHY_READ 0x7e ++#define CARRIER_SENSE_COUNTER 0x79 //byte ++#define SECURITY 0x5f ++#define SECURITY_WEP_TX_ENABLE_SHIFT 1 ++#define SECURITY_WEP_RX_ENABLE_SHIFT 0 ++#define SECURITY_ENCRYP_104 1 ++#define SECURITY_ENCRYP_SHIFT 4 ++#define SECURITY_ENCRYP_MASK ((1<<4)|(1<<5)) ++#define KEY0 0x90 ++#define CONFIG2_ANTENNA_SHIFT 6 ++#define TX_BEACON_RING_ADDR 0x4c ++#define CONFIG0_WEP40_SHIFT 7 ++#define CONFIG0_WEP104_SHIFT 6 ++#define AGCRESET_SHIFT 5 ++ ++ ++ ++/* ++ * Operational registers offsets in PCI (I/O) space. ++ * RealTek names are used. ++ */ ++ ++#define IDR0 0x0000 ++#define IDR1 0x0001 ++#define IDR2 0x0002 ++#define IDR3 0x0003 ++#define IDR4 0x0004 ++#define IDR5 0x0005 ++ ++/* 0x0006 - 0x0007 - reserved */ ++ ++#define MAR0 0x0008 ++#define MAR1 0x0009 ++#define MAR2 0x000A ++#define MAR3 0x000B ++#define MAR4 0x000C ++#define MAR5 0x000D ++#define MAR6 0x000E ++#define MAR7 0x000F ++ ++/* 0x0010 - 0x0017 - reserved */ ++ ++#define TSFTR 0x0018 ++#define TSFTR_END 0x001F ++ ++#define TLPDA 0x0020 ++#define TLPDA_END 0x0023 ++#define TNPDA 0x0024 ++#define TNPDA_END 0x0027 ++#define THPDA 0x0028 ++#define THPDA_END 0x002B ++ ++#define BRSR_8187 0x002C ++#define BRSR_8187_END 0x002D ++#define BRSR_8187B 0x0034 ++#define BRSR_8187B_END 0x0035 ++ ++#define BSSID 0x002E ++#define BSSID_END 0x0033 ++ ++/* 0x0034 - 0x0034 - reserved */ ++ ++/* 0x0038 - 0x003B - reserved */ ++ ++#define IMR 0x003C ++#define IMR_END 0x003D ++ ++#define ISR 0x003E ++#define ISR_END 0x003F ++ ++#define TCR 0x0040 ++#define TCR_END 0x0043 ++ ++#define RCR 0x0044 ++#define RCR_END 0x0047 ++ ++#define TimerInt 0x0048 ++#define TimerInt_END 0x004B ++ ++#define TBDA 0x004C ++#define TBDA_END 0x004F ++ ++#define CR9346 0x0050 ++ ++#define CONFIG0 0x0051 ++#define CONFIG1 0x0052 ++#define CONFIG2 0x0053 ++ ++#define ANA_PARAM 0x0054 ++#define ANA_PARAM_END 0x0x0057 ++ ++#define MSR 0x0058 ++ ++#define CONFIG3 0x0059 ++#define CONFIG4 0x005A ++ ++#define TESTR 0x005B ++ ++/* 0x005C - 0x005D - reserved */ ++#define TFPC_AC 0x005C ++#define PSR 0x005E ++ ++#define SCR 0x005F ++ ++/* 0x0060 - 0x006F - reserved */ ++#define ANA_PARAM2 0x0060 ++#define ANA_PARAM2_END 0x0063 ++ ++#define BcnIntv 0x0070 ++#define BcnItv_END 0x0071 ++ ++#define AtimWnd 0x0072 ++#define AtimWnd_END 0x0073 ++ ++#define BintrItv 0x0074 ++#define BintrItv_END 0x0075 ++ ++#define AtimtrItv 0x0076 ++#define AtimtrItv_END 0x0077 ++ ++#define PhyDelay 0x0078 ++ ++//#define CRCount 0x0079 ++ ++#define AckTimeOutReg 0x79 // ACK timeout register, in unit of 4 us. ++/* 0x007A - 0x007B - reserved */ ++#define BBAddr 0x007C ++ ++ ++#define PhyAddr 0x007C ++#define PhyDataW 0x007D ++#define PhyDataR 0x007E ++#define RF_Ready 0x007F ++ ++#define PhyCFG 0x0080 ++#define PhyCFG_END 0x0083 ++ ++/* following are for rtl8185 */ ++#define RFPinsOutput 0x80 ++#define RFPinsEnable 0x82 ++#define RF_TIMING 0x8c ++#define RFPinsSelect 0x84 ++#define ANAPARAM2 0x60 ++#define RF_PARA 0x88 ++#define RFPinsInput 0x86 ++#define GP_ENABLE 0x90 ++#define GPIO 0x91 ++#define HSSI_PARA 0x94 // HSS Parameter ++#define SW_CONTROL_GPIO 0x400 ++#define CCK_TXAGC 0x9d ++#define OFDM_TXAGC 0x9e ++#define ANTSEL 0x9f ++#define TXAGC_CTL_PER_PACKET_ANT_SEL 0x02 ++#define WPA_CONFIG 0xb0 ++#define TX_AGC_CTL 0x9c ++#define TX_AGC_CTL_PER_PACKET_TXAGC 0x01 ++#define TX_AGC_CTL_PERPACKET_GAIN_SHIFT 0 ++#define TX_AGC_CTL_PERPACKET_ANTSEL_SHIFT 1 ++#define TX_AGC_CTL_FEEDBACK_ANT 2 ++#define RESP_RATE 0x34 ++#define SIFS 0xb4 ++#define DIFS 0xb5 ++#define EIFS_8187 0x35 ++#define EIFS_8187B 0x2D ++#define SLOT 0xb6 ++#define CW_VAL 0xbd ++#define CW_CONF 0xbc ++#define CW_CONF_PERPACKET_RETRY_LIMIT 0x02 ++#define CW_CONF_PERPACKET_CW 0x01 ++#define CW_CONF_PERPACKET_RETRY_SHIFT 1 ++#define CW_CONF_PERPACKET_CW_SHIFT 0 ++#define MAX_RESP_RATE_SHIFT 4 ++#define MIN_RESP_RATE_SHIFT 0 ++#define RATE_FALLBACK 0xbe ++#define RATE_FALLBACK_CTL_ENABLE 0x80 ++#define RATE_FALLBACK_CTL_AUTO_STEP0 0x00 ++ ++#define ARFR 0x1E0 // Auto Rate Fallback Register (0x1e0 ~ 0x1e2) ++#define RMS 0x1EC // Rx Max Pacetk Size (0x1ec[0:12]) ++ ++/* ++ * 0x0084 - 0x00D3 is selected to page 1 when PSEn bit (bit0, PSR) ++ * is set to 1 ++ */ ++ ++#define Wakeup0 0x0084 ++#define Wakeup0_END 0x008B ++ ++#define Wakeup1 0x008C ++#define Wakeup1_END 0x0093 ++ ++#define Wakeup2LD 0x0094 ++#define Wakeup2LD_END 0x009B ++#define Wakeup2HD 0x009C ++#define Wakeup2HD_END 0x00A3 ++ ++#define Wakeup3LD 0x00A4 ++#define Wakeup3LD_END 0x00AB ++#define Wakeup3HD 0x00AC ++#define Wakeup3HD_END 0x00B3 ++ ++#define Wakeup4LD 0x00B4 ++#define Wakeup4LD_END 0x00BB ++#define Wakeup4HD 0x00BC ++#define Wakeup4HD_END 0x00C3 ++ ++#define CRC0 0x00C4 ++#define CRC0_END 0x00C5 ++#define CRC1 0x00C6 ++#define CRC1_END 0x00C7 ++#define CRC2 0x00C8 ++#define CRC2_END 0x00C9 ++#define CRC3 0x00CA ++#define CRC3_END 0x00CB ++#define CRC4 0x00CC ++#define CRC4_END 0x00CD ++ ++/* 0x00CE - 0x00D3 - reserved */ ++ ++ ++ ++/* ++ * 0x0084 - 0x00D3 is selected to page 0 when PSEn bit (bit0, PSR) ++ * is set to 0 ++ */ ++ ++/* 0x0084 - 0x008F - reserved */ ++ ++#define DK0 0x0090 ++#define DK0_END 0x009F ++#define DK1 0x00A0 ++#define DK1_END 0x00AF ++#define DK2 0x00B0 ++#define DK2_END 0x00BF ++#define DK3 0x00C0 ++#define DK3_END 0x00CF ++ ++#define GPO 0x90 ++#define GPE 0x91 ++#define GPI 0x92 ++ ++#define RFTiming 0x008C ++#define ACM_CONTROL 0x00BF // ACM Control Registe ++#define INT_MIG 0x00E2 // Interrupt Migration (0xE2 ~ 0xE3) ++#define TID_AC_MAP 0x00E8 // TID to AC Mapping Register ++ ++#define AC_VO_PARAM 0x00F0 // AC_VO Parameters Record ++#define AC_VI_PARAM 0x00F4 // AC_VI Parameters Record ++#define AC_BE_PARAM 0x00F8 // AC_BE Parameters Record ++#define AC_BK_PARAM 0x00FC // AC_BK Parameters Record ++ ++/* 0x00D0 - 0x00D3 - reserved */ ++#define CCK_FALSE_ALARM 0x00D0 ++#define OFDM_FALSE_ALARM 0x00D2 ++ ++ ++/* 0x00D4 - 0x00D7 - reserved */ ++ ++#define CONFIG5 0x00D8 ++ ++#define TPPoll 0x00D9 ++ ++/* 0x00DA - 0x00DB - reserved */ ++ ++#define CWR 0x00DC ++#define CWR_END 0x00DD ++ ++#define RetryCTR 0x00DE ++ ++/* 0x00DF - 0x00E3 - reserved */ ++ ++#define RDSAR 0x00E4 ++#define RDSAR_END 0x00E7 ++ ++/* 0x00E8 - 0x00EF - reserved */ ++#define ANA_PARAM3 0x00EE ++ ++#define FER 0x00F0 ++#define FER_END 0x00F3 ++ ++#define FEMR 0x1D4 // Function Event Mask register (0xf4 ~ 0xf7) ++//#define FEMR 0x00F4 ++#define FEMR_END 0x00F7 ++ ++#define FPSR 0x00F8 ++#define FPSR_END 0x00FB ++ ++#define FFER 0x00FC ++#define FFER_END 0x00FF ++ ++/* ++ * 0x0000 - 0x00ff is selected to page 0 when PSEn bit (bit0, PSR) ++ * is set to 2 ++ */ ++#define RFSW_CTRL 0x272 // 0x272-0x273. ++ ++ ++ ++//---------------------------------------------------------------------------- ++// 8187B AC_XX_PARAM bits ++//---------------------------------------------------------------------------- ++#define AC_PARAM_TXOP_LIMIT_OFFSET 16 ++#define AC_PARAM_ECW_MAX_OFFSET 12 ++#define AC_PARAM_ECW_MIN_OFFSET 8 ++#define AC_PARAM_AIFS_OFFSET 0 ++ ++//---------------------------------------------------------------------------- ++// 8187B ACM_CONTROL bits (Offset 0xBF, 1 Byte) ++//---------------------------------------------------------------------------- ++#define VOQ_ACM_EN (0x01 << 7) //BIT7 ++#define VIQ_ACM_EN (0x01 << 6) //BIT6 ++#define BEQ_ACM_EN (0x01 << 5) //BIT5 ++#define ACM_HW_EN (0x01 << 4) //BIT4 ++#define TXOPSEL (0x01 << 3) //BIT3 ++#define VOQ_ACM_CTL (0x01 << 2) //BIT2 // Set to 1 when AC_VO used time reaches or exceeds the admitted time ++#define VIQ_ACM_CTL (0x01 << 1) //BIT1 // Set to 1 when AC_VI used time reaches or exceeds the admitted time ++#define BEQ_ACM_CTL (0x01 << 0) //BIT0 // Set to 1 when AC_BE used time reaches or exceeds the admitted time ++ ++//---------------------------------------------------------------------------- ++// 8187B RF pins related setting (offset 0xFF80-0xFF87,) ++//---------------------------------------------------------------------------- ++#define TR_SW_MASK_TX_8187 BIT5 ++#define TR_SW_MASK_RX_8187 BIT6 ++#define TR_SW_MASK_8187 (TR_SW_MASK_TX_8187 | TR_SW_MASK_RX_8187) ++ ++/* ++ * Bitmasks for specific register functions. ++ * Names are derived from the register name and function name. ++ * ++ * <REGISTER>_<FUNCTION>[<bit>] ++ * ++ * this leads to some awkward names... ++ */ ++ ++#define BRSR_BPLCP ((1<< 8)) ++#define BRSR_MBR ((1<< 1)|(1<< 0)) ++#define BRSR_MBR_8185 ((1<< 11)|(1<< 10)|(1<< 9)|(1<< 8)|(1<< 7)|(1<< 6)|(1<< 5)|(1<< 4)|(1<< 3)|(1<< 2)|(1<< 1)|(1<< 0)) ++#define BRSR_MBR0 ((1<< 0)) ++#define BRSR_MBR1 ((1<< 1)) ++ ++#define CR_RST ((1<< 4)) ++#define CR_RE ((1<< 3)) ++#define CR_TE ((1<< 2)) ++#define CR_MulRW ((1<< 0)) ++ ++#define IMR_TXFOVW ((1<<15)) ++#define IMR_TimeOut ((1<<14)) ++#define IMR_BcnInt ((1<<13)) ++#define IMR_ATIMInt ((1<<12)) ++#define IMR_TBDER ((1<<11)) ++#define IMR_TBDOK ((1<<10)) ++#define IMR_THPDER ((1<< 9)) ++#define IMR_THPDOK ((1<< 8)) ++#define IMR_TNPDER ((1<< 7)) ++#define IMR_TNPDOK ((1<< 6)) ++#define IMR_RXFOVW ((1<< 5)) ++#define IMR_RDU ((1<< 4)) ++#define IMR_TLPDER ((1<< 3)) ++#define IMR_TLPDOK ((1<< 2)) ++#define IMR_RER ((1<< 1)) ++#define IMR_ROK ((1<< 0)) ++ ++#define ISR_TXFOVW ((1<<15)) ++#define ISR_TimeOut ((1<<14)) ++#define ISR_BcnInt ((1<<13)) ++#define ISR_ATIMInt ((1<<12)) ++#define ISR_TBDER ((1<<11)) ++#define ISR_TBDOK ((1<<10)) ++#define ISR_THPDER ((1<< 9)) ++#define ISR_THPDOK ((1<< 8)) ++#define ISR_TNPDER ((1<< 7)) ++#define ISR_TNPDOK ((1<< 6)) ++#define ISR_RXFOVW ((1<< 5)) ++#define ISR_RDU ((1<< 4)) ++#define ISR_TLPDER ((1<< 3)) ++#define ISR_TLPDOK ((1<< 2)) ++#define ISR_RER ((1<< 1)) ++#define ISR_ROK ((1<< 0)) ++ ++#define HW_VERID_R8180_F 3 ++#define HW_VERID_R8180_ABCD 2 ++#define HW_VERID_R8185_ABC 4 ++#define HW_VERID_R8185_D 5 ++ ++#define TCR_DurProcMode ((1<<30)) ++#define TCR_DISReqQsize ((1<<28)) ++#define TCR_HWVERID_MASK ((1<<27)|(1<<26)|(1<<25)) ++#define TCR_HWVERID_SHIFT 25 ++#define TCR_SWPLCPLEN ((1<<24)) ++#define TCR_PLCP_LEN TCR_SAT // rtl8180 ++#define TCR_MXDMA_MASK ((1<<23)|(1<<22)|(1<<21)) ++#define TCR_MXDMA_1024 6 ++#define TCR_MXDMA_2048 7 ++#define TCR_MXDMA_SHIFT 21 ++#define TCR_DISCW ((1<<20)) ++#define TCR_ICV ((1<<19)) ++#define TCR_LBK ((1<<18)|(1<<17)) ++#define TCR_LBK1 ((1<<18)) ++#define TCR_LBK0 ((1<<17)) ++#define TCR_CRC ((1<<16)) ++#define TCR_SRL_MASK ((1<<15)|(1<<14)|(1<<13)|(1<<12)|(1<<11)|(1<<10)|(1<<9)|(1<<8)) ++#define TCR_LRL_MASK ((1<<0)|(1<<1)|(1<<2)|(1<<3)|(1<<4)|(1<<5)|(1<<6)|(1<<7)) ++#define TCR_PROBE_NOTIMESTAMP_SHIFT 29 //rtl8185 ++ ++#define RCR_ONLYERLPKT ((1<<31)) ++#define RCR_CS_SHIFT 29 ++#define RCR_CS_MASK ((1<<30) | (1<<29)) ++#define RCR_ENMARP ((1<<28)) ++#define RCR_CBSSID ((1<<23)) ++#define RCR_APWRMGT ((1<<22)) ++#define RCR_ADD3 ((1<<21)) ++#define RCR_AMF ((1<<20)) ++#define RCR_ACF ((1<<19)) ++#define RCR_ADF ((1<<18)) ++#define RCR_RXFTH ((1<<15)|(1<<14)|(1<<13)) ++#define RCR_RXFTH2 ((1<<15)) ++#define RCR_RXFTH1 ((1<<14)) ++#define RCR_RXFTH0 ((1<<13)) ++#define RCR_AICV ((1<<12)) ++#define RCR_MXDMA ((1<<10)|(1<< 9)|(1<< 8)) ++#define RCR_MXDMA2 ((1<<10)) ++#define RCR_MXDMA1 ((1<< 9)) ++#define RCR_MXDMA0 ((1<< 8)) ++#define RCR_9356SEL ((1<< 6)) ++#define RCR_ACRC32 ((1<< 5)) ++#define RCR_AB ((1<< 3)) ++#define RCR_AM ((1<< 2)) ++#define RCR_APM ((1<< 1)) ++#define RCR_AAP ((1<< 0)) ++ ++#define CR9346_EEM ((1<<7)|(1<<6)) ++#define CR9346_EEM1 ((1<<7)) ++#define CR9346_EEM0 ((1<<6)) ++#define CR9346_EECS ((1<<3)) ++#define CR9346_EESK ((1<<2)) ++#define CR9346_EED1 ((1<<1)) ++#define CR9346_EED0 ((1<<0)) ++ ++#define CONFIG0_WEP104 ((1<<6)) ++#define CONFIG0_LEDGPO_En ((1<<4)) ++#define CONFIG0_Aux_Status ((1<<3)) ++#define CONFIG0_GL ((1<<1)|(1<<0)) ++#define CONFIG0_GL1 ((1<<1)) ++#define CONFIG0_GL0 ((1<<0)) ++ ++#define CONFIG1_LEDS ((1<<7)|(1<<6)) ++#define CONFIG1_LEDS1 ((1<<7)) ++#define CONFIG1_LEDS0 ((1<<6)) ++#define CONFIG1_LWACT ((1<<4)) ++#define CONFIG1_MEMMAP ((1<<3)) ++#define CONFIG1_IOMAP ((1<<2)) ++#define CONFIG1_VPD ((1<<1)) ++#define CONFIG1_PMEn ((1<<0)) ++ ++#define CONFIG2_LCK ((1<<7)) ++#define CONFIG2_ANT ((1<<6)) ++#define CONFIG2_DPS ((1<<3)) ++#define CONFIG2_PAPE_sign ((1<<2)) ++#define CONFIG2_PAPE_time ((1<<1)|(1<<0)) ++#define CONFIG2_PAPE_time1 ((1<<1)) ++#define CONFIG2_PAPE_time0 ((1<<0)) ++ ++#define CONFIG3_GNTSel ((1<<7)) ++#define CONFIG3_PARM_En ((1<<6)) ++#define CONFIG3_Magic ((1<<5)) ++#define CONFIG3_CardB_En ((1<<3)) ++#define CONFIG3_CLKRUN_En ((1<<2)) ++#define CONFIG3_FuncRegEn ((1<<1)) ++#define CONFIG3_FBtbEn ((1<<0)) ++ ++#define CONFIG4_VCOPDN ((1<<7)) ++#define CONFIG4_PWROFF ((1<<6)) ++#define CONFIG4_PWRMGT ((1<<5)) ++#define CONFIG4_LWPME ((1<<4)) ++#define CONFIG4_LWPTN ((1<<2)) ++#define CONFIG4_RFTYPE ((1<<1)|(1<<0)) ++#define CONFIG4_RFTYPE1 ((1<<1)) ++#define CONFIG4_RFTYPE0 ((1<<0)) ++ ++#define CONFIG5_TX_FIFO_OK ((1<<7)) ++#define CONFIG5_RX_FIFO_OK ((1<<6)) ++#define CONFIG5_CALON ((1<<5)) ++#define CONFIG5_EACPI ((1<<2)) ++#define CONFIG5_LANWake ((1<<1)) ++#define CONFIG5_PME_STS ((1<<0)) ++ ++#define MSR_LINK_MASK ((1<<2)|(1<<3)) ++#define MSR_LINK_MANAGED 2 ++#define MSR_LINK_NONE 0 ++#define MSR_LINK_SHIFT 2 ++#define MSR_LINK_ADHOC 1 ++#define MSR_LINK_MASTER 3 ++#define MSR_LINK_ENEDCA (1<<4) ++ ++#define PSR_GPO ((1<<7)) ++#define PSR_GPI ((1<<6)) ++#define PSR_LEDGPO1 ((1<<5)) ++#define PSR_LEDGPO0 ((1<<4)) ++#define PSR_UWF ((1<<1)) ++#define PSR_PSEn ((1<<0)) ++ ++#define SCR_KM ((1<<5)|(1<<4)) ++#define SCR_KM1 ((1<<5)) ++#define SCR_KM0 ((1<<4)) ++#define SCR_TXSECON ((1<<1)) ++#define SCR_RXSECON ((1<<0)) ++ ++#define BcnItv_BcnItv (0x01FF) ++ ++#define AtimWnd_AtimWnd (0x01FF) ++ ++#define BintrItv_BintrItv (0x01FF) ++ ++#define AtimtrItv_AtimtrItv (0x01FF) ++ ++#define PhyDelay_PhyDelay ((1<<2)|(1<<1)|(1<<0)) ++ ++#define TPPoll_BQ ((1<<7)) ++#define TPPoll_HPQ ((1<<6)) ++#define TPPoll_NPQ ((1<<5)) ++#define TPPoll_LPQ ((1<<4)) ++#define TPPoll_SBQ ((1<<3)) ++#define TPPoll_SHPQ ((1<<2)) ++#define TPPoll_SNPQ ((1<<1)) ++#define TPPoll_SLPQ ((1<<0)) ++ ++#define CWR_CW (0x01FF) ++ ++#define FER_INTR ((1<<15)) ++#define FER_GWAKE ((1<< 4)) ++ ++#define FEMR_INTR ((1<<15)) ++#define FEMR_WKUP ((1<<14)) ++#define FEMR_GWAKE ((1<< 4)) ++ ++#define FPSR_INTR ((1<<15)) ++#define FPSR_GWAKE ((1<< 4)) ++ ++#define FFER_INTR ((1<<15)) ++#define FFER_GWAKE ((1<< 4)) ++ ++ ++//---------------------------------------------------------------------------- ++// 818xB AnaParm & AnaParm2 Register ++//---------------------------------------------------------------------------- ++/* ++#ifdef RTL8185B_FPGA ++#define ANAPARM_FPGA_ON 0xa0000b59 ++//#define ANAPARM_FPGA_OFF ++#define ANAPARM2_FPGA_ON 0x860dec11 ++//#define ANAPARM2_FPGA_OFF ++#else //ASIC ++*/ ++#define ANAPARM_ASIC_ON 0x45090658 ++//#define ANAPARM_ASIC_OFF ++#define ANAPARM2_ASIC_ON 0x727f3f52 ++//#define ANAPARM2_ASIC_OFF ++//#endif ++//by amy for power save ++#define RF_CHANGE_BY_SW BIT31 ++#define RF_CHANGE_BY_HW BIT30 ++#define RF_CHANGE_BY_PS BIT29 ++#define RF_CHANGE_BY_IPS BIT28 ++#define ANAPARM_ASIC_ON 0x45090658 ++#define ANAPARM2_ASIC_ON 0x727f3f52 ++ ++#define ANAPARM_ON ANAPARM_ASIC_ON ++#define ANAPARM2_ON ANAPARM2_ASIC_ON ++#define TFPC 0x5C // Tx FIFO Packet Count for BK, BE, VI, VO queues (2 bytes) ++#define Config4_PowerOff BIT6 // Turn ON/Off RF Power(RFMD) ++#define ANAPARM_OFF 0x51480658 ++#define ANAPARM2_OFF 0x72003f70 ++//by amy for power save ++ ++#define MAX_DOZE_WAITING_TIMES_87B 500 ++ ++#endif +diff -Nur linux-2.6.33/drivers/net/wireless/rtl8187b/r8180_pm.c linux-lemote/drivers/net/wireless/rtl8187b/r8180_pm.c +--- linux-2.6.33/drivers/net/wireless/rtl8187b/r8180_pm.c 1970-01-01 01:00:00.000000000 +0100 ++++ linux-lemote/drivers/net/wireless/rtl8187b/r8180_pm.c 2010-03-06 16:43:22.000000000 +0100 +@@ -0,0 +1,97 @@ ++/* ++ Power management interface routines. ++ Written by Mariusz Matuszek. ++ This code is currently just a placeholder for later work and ++ does not do anything useful. ++ ++ This is part of rtl8180 OpenSource driver. ++ Copyright (C) Andrea Merello 2004 <andreamrl@tiscali.it> ++ Released under the terms of GPL (General Public Licence) ++*/ ++ ++#ifdef CONFIG_RTL8180_PM ++ ++ ++#include "r8180_hw.h" ++#include "r8180_pm.h" ++#include "r8187.h" ++int rtl8180_save_state (struct pci_dev *dev, u32 state) ++{ ++ printk(KERN_NOTICE "r8180 save state call (state %u).\n", state); ++ return(-EAGAIN); ++} ++ ++//netif_running is set to 0 before system call rtl8180_close, ++//netif_running is set to 1 before system call rtl8180_open, ++//if open success it will not change, or it change to 0; ++int rtl8187_suspend (struct usb_interface *intf, pm_message_t state) ++{ ++ struct r8180_priv *priv; ++#if LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0) ++ struct net_device *dev = usb_get_intfdata(intf); ++#else ++ //struct net_device *dev = (struct net_device *)ptr; ++#endif ++ ++ printk("====>%s \n", __func__); ++ priv=ieee80211_priv(dev); ++ ++ if(dev) { ++ /* save the old rfkill state and then power off it */ ++ priv->eInactivePowerState = priv->eRFPowerState; ++ /* power off the wifi by default */ ++ r8187b_wifi_change_rfkill_state(dev, eRfOff); ++ ++ if (!netif_running(dev)) { ++ //printk(KERN_WARNING "UI or other close dev before suspend, go out suspend function\n"); ++ return 0; ++ } ++ ++ dev->netdev_ops->ndo_stop(dev); ++ netif_device_detach(dev); ++ } ++ return 0; ++} ++ ++ ++int rtl8187_resume (struct usb_interface *intf) ++{ ++ struct r8180_priv *priv; ++#if LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0) ++ struct net_device *dev = usb_get_intfdata(intf); ++#else ++ //struct net_device *dev = (struct net_device *)ptr; ++#endif ++ ++ printk("====>%s \n", __func__); ++ priv=ieee80211_priv(dev); ++ ++ if(dev) { ++ /* resume the old rfkill state */ ++ r8187b_wifi_change_rfkill_state(dev, priv->eInactivePowerState); ++ ++ if (!netif_running(dev)){ ++ //printk(KERN_WARNING "UI or other close dev before suspend, go out resume function\n"); ++ return 0; ++ } ++ ++ netif_device_attach(dev); ++ dev->netdev_ops->ndo_open(dev); ++ } ++ ++ return 0; ++} ++ ++ ++int rtl8180_enable_wake (struct pci_dev *dev, u32 state, int enable) ++{ ++ ++ //printk(KERN_NOTICE "r8180 enable wake call (state %u, enable %d).\n", ++ // state, enable); ++ return 0; ++ //return(-EAGAIN); ++} ++ ++ ++ ++#endif //CONFIG_RTL8180_PM +diff -Nur linux-2.6.33/drivers/net/wireless/rtl8187b/r8180_pm.h linux-lemote/drivers/net/wireless/rtl8187b/r8180_pm.h +--- linux-2.6.33/drivers/net/wireless/rtl8187b/r8180_pm.h 1970-01-01 01:00:00.000000000 +0100 ++++ linux-lemote/drivers/net/wireless/rtl8187b/r8180_pm.h 2010-03-06 16:43:22.000000000 +0100 +@@ -0,0 +1,28 @@ ++/* ++ Power management interface routines. ++ Written by Mariusz Matuszek. ++ This code is currently just a placeholder for later work and ++ does not do anything useful. ++ ++ This is part of rtl8180 OpenSource driver. ++ Copyright (C) Andrea Merello 2004 <andreamrl@tiscali.it> ++ Released under the terms of GPL (General Public Licence) ++ ++*/ ++ ++#ifdef CONFIG_RTL8180_PM ++ ++#ifndef R8180_PM_H ++#define R8180_PM_H ++ ++#include <linux/types.h> ++#include <linux/usb.h> ++ ++int rtl8180_save_state (struct pci_dev *dev, u32 state); ++int rtl8187_suspend (struct usb_interface *intf,pm_message_t state); ++int rtl8187_resume (struct usb_interface *intf); ++int rtl8180_enable_wake (struct pci_dev *dev, u32 state, int enable); ++ ++#endif //R8180_PM_H ++ ++#endif // CONFIG_RTL8180_PM +diff -Nur linux-2.6.33/drivers/net/wireless/rtl8187b/r8180_rtl8225.c linux-lemote/drivers/net/wireless/rtl8187b/r8180_rtl8225.c +--- linux-2.6.33/drivers/net/wireless/rtl8187b/r8180_rtl8225.c 1970-01-01 01:00:00.000000000 +0100 ++++ linux-lemote/drivers/net/wireless/rtl8187b/r8180_rtl8225.c 2010-03-06 16:43:22.000000000 +0100 +@@ -0,0 +1,1007 @@ ++/* ++ This is part of the rtl8180-sa2400 driver ++ released under the GPL (See file COPYING for details). ++ Copyright (c) 2005 Andrea Merello <andreamrl@tiscali.it> ++ ++ This files contains programming code for the rtl8225 ++ radio frontend. ++ ++ *Many* thanks to Realtek Corp. for their great support! ++ ++*/ ++ ++ ++ ++#include "r8180_hw.h" ++#include "r8180_rtl8225.h" ++#ifdef ENABLE_DOT11D ++#include "dot11d.h" ++#endif ++ ++#define USE_8051_3WIRE 1 ++ ++u8 rtl8225_threshold[]={ ++ 0x8d, 0x8d, 0x8d, 0x8d, 0x9d, 0xad, 0xbd, ++}; ++ ++u8 rtl8225_gain[]={ ++ 0x23,0x88,0x7c,0xa5,// -82dbm ++ 0x23,0x88,0x7c,0xb5,// -82dbm ++ 0x23,0x88,0x7c,0xc5,// -82dbm ++ 0x33,0x80,0x79,0xc5,// -78dbm ++ 0x43,0x78,0x76,0xc5,// -74dbm ++ 0x53,0x60,0x73,0xc5,// -70dbm ++ 0x63,0x58,0x70,0xc5,// -66dbm ++}; ++ ++u16 rtl8225bcd_rxgain[]={ ++ 0x0400, 0x0401, 0x0402, 0x0403, 0x0404, 0x0405, 0x0408, 0x0409, ++ 0x040a, 0x040b, 0x0502, 0x0503, 0x0504, 0x0505, 0x0540, 0x0541, ++ 0x0542, 0x0543, 0x0544, 0x0545, 0x0580, 0x0581, 0x0582, 0x0583, ++ 0x0584, 0x0585, 0x0588, 0x0589, 0x058a, 0x058b, 0x0643, 0x0644, ++ 0x0645, 0x0680, 0x0681, 0x0682, 0x0683, 0x0684, 0x0685, 0x0688, ++ 0x0689, 0x068a, 0x068b, 0x068c, 0x0742, 0x0743, 0x0744, 0x0745, ++ 0x0780, 0x0781, 0x0782, 0x0783, 0x0784, 0x0785, 0x0788, 0x0789, ++ 0x078a, 0x078b, 0x078c, 0x078d, 0x0790, 0x0791, 0x0792, 0x0793, ++ 0x0794, 0x0795, 0x0798, 0x0799, 0x079a, 0x079b, 0x079c, 0x079d, ++ 0x07a0, 0x07a1, 0x07a2, 0x07a3, 0x07a4, 0x07a5, 0x07a8, 0x07a9, ++ 0x07aa, 0x07ab, 0x07ac, 0x07ad, 0x07b0, 0x07b1, 0x07b2, 0x07b3, ++ 0x07b4, 0x07b5, 0x07b8, 0x07b9, 0x07ba, 0x07bb, 0x07bb ++ ++}; ++ ++ ++ ++u8 rtl8225_tx_gain_cck_ofdm[]={ ++ 0x02,0x06,0x0e,0x1e,0x3e,0x7e ++}; ++ ++ ++u8 rtl8225_tx_power_ofdm[]={ ++ 0x80,0x90,0xa2,0xb5,0xcb,0xe4 ++}; ++ ++ ++u8 rtl8225_tx_power_cck_ch14[]={ ++ 0x18,0x17,0x15,0x0c,0x00,0x00,0x00,0x00, ++ 0x1b,0x1a,0x17,0x0e,0x00,0x00,0x00,0x00, ++ 0x1f,0x1e,0x1a,0x0f,0x00,0x00,0x00,0x00, ++ 0x22,0x21,0x1d,0x11,0x00,0x00,0x00,0x00, ++ 0x26,0x25,0x21,0x13,0x00,0x00,0x00,0x00, ++ 0x2b,0x2a,0x25,0x15,0x00,0x00,0x00,0x00 ++}; ++ ++ ++u8 rtl8225_tx_power_cck[]={ ++ 0x18,0x17,0x15,0x11,0x0c,0x08,0x04,0x02, ++ 0x1b,0x1a,0x17,0x13,0x0e,0x09,0x04,0x02, ++ 0x1f,0x1e,0x1a,0x15,0x10,0x0a,0x05,0x02, ++ 0x22,0x21,0x1d,0x18,0x11,0x0b,0x06,0x02, ++ 0x26,0x25,0x21,0x1b,0x14,0x0d,0x06,0x03, ++ 0x2b,0x2a,0x25,0x1e,0x16,0x0e,0x07,0x03 ++}; ++ ++u8 rtl8225_agc[]={ ++ 0x9e,0x9e,0x9e,0x9e,0x9e,0x9e,0x9e,0x9e,0x9d,0x9c,0x9b,0x9a,0x99,0x98,0x97,0x96, ++ 0x95,0x94,0x93,0x92,0x91,0x90,0x8f,0x8e,0x8d,0x8c,0x8b,0x8a,0x89,0x88,0x87,0x86, ++ 0x85,0x84,0x83,0x82,0x81,0x80,0x3f,0x3e,0x3d,0x3c,0x3b,0x3a,0x39,0x38,0x37,0x36, ++ 0x35,0x34,0x33,0x32,0x31,0x30,0x2f,0x2e,0x2d,0x2c,0x2b,0x2a,0x29,0x28,0x27,0x26, ++ 0x25,0x24,0x23,0x22,0x21,0x20,0x1f,0x1e,0x1d,0x1c,0x1b,0x1a,0x19,0x18,0x17,0x16, ++ 0x15,0x14,0x13,0x12,0x11,0x10,0x0f,0x0e,0x0d,0x0c,0x0b,0x0a,0x09,0x08,0x07,0x06, ++ 0x05,0x04,0x03,0x02,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01, ++ 0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01, ++}; ++ ++u32 rtl8225_chan[] = { ++ 0, //dummy channel 0 ++ 0x085c, //1 ++ 0x08dc, //2 ++ 0x095c, //3 ++ 0x09dc, //4 ++ 0x0a5c, //5 ++ 0x0adc, //6 ++ 0x0b5c, //7 ++ 0x0bdc, //8 ++ 0x0c5c, //9 ++ 0x0cdc, //10 ++ 0x0d5c, //11 ++ 0x0ddc, //12 ++ 0x0e5c, //13 ++ //0x0f5c, //14 ++ 0x0f72, // 14 ++}; ++ ++void rtl8225_set_gain(struct net_device *dev, short gain) ++{ ++ write_phy_ofdm(dev, 0x0d, rtl8225_gain[gain * 4]); ++ write_phy_ofdm(dev, 0x1b, rtl8225_gain[gain * 4 + 2]); ++ write_phy_ofdm(dev, 0x1d, rtl8225_gain[gain * 4 + 3]); ++ write_phy_ofdm(dev, 0x23, rtl8225_gain[gain * 4 + 1]); ++ ++} ++ ++ ++void write_rtl8225(struct net_device *dev, u8 adr, u16 data) ++{ ++//in windows the delays in this function was del from 85 to 87, ++//here we mod to sleep, or The CPU occupany is too hight. LZM 31/10/2008 ++ ++#ifdef USE_8051_3WIRE ++ ++ struct r8180_priv *priv = (struct r8180_priv *)ieee80211_priv(dev); ++ struct usb_device *udev = priv->udev; ++ //u8 bit; ++ //u16 wReg80, wReg82, wReg84; ++ u16 wReg80, wReg84; ++ ++ wReg80 = read_nic_word(dev, RFPinsOutput); ++ wReg80 &= 0xfff3; ++// wReg82 = read_nic_word(dev, RFPinsEnable); ++ wReg84 = read_nic_word(dev, RFPinsSelect); ++ // <RJ_NOTE> 3-wire should be controled by HW when we finish SW 3-wire programming. 2005.08.10, by rcnjko. ++ //wReg84 &= 0xfff0; ++ wReg84 &= 0xfff8; //modified by david according to windows segment code. ++ ++ // We must set SW enabled before terminating HW 3-wire, 2005.07.29, by rcnjko. ++// write_nic_word(dev, RFPinsEnable, (wReg82|0x0007)); // Set To Output Enable ++ write_nic_word(dev, RFPinsSelect, (wReg84|0x0007)); // Set To SW Switch ++// force_pci_posting(dev); ++// udelay(10); // ++ ++ write_nic_word(dev, 0x80, (BB_HOST_BANG_EN|wReg80)); // Set SI_EN (RFLE) ++// force_pci_posting(dev); ++// udelay(2); ++ //twreg.struc.enableB = 0; ++ write_nic_word(dev, 0x80, (wReg80)); // Clear SI_EN (RFLE) ++// force_pci_posting(dev); ++// udelay(10); ++ ++ usb_control_msg(udev, usb_sndctrlpipe(udev, 0), ++ RTL8187_REQ_SET_REGS, RTL8187_REQT_WRITE, ++ adr, 0x8225, &data, 2, HZ / 2); ++ ++ // write_nic_word(dev, 0x80, (BB_HOST_BANG_EN|wReg80)); ++// force_pci_posting(dev); ++// udelay(10); ++ ++ write_nic_word(dev, 0x80, (wReg80|0x0004)); ++ write_nic_word(dev, 0x84, (wReg84|0x0000));// Set To SW Switch ++ ++ if(priv->card_type == USB) ++ ;// msleep(2); ++ else ++ ; // rtl8185_rf_pins_enable(dev); ++ ++#else ++ int i; ++ u16 out,select; ++ u8 bit; ++ u32 bangdata = (data << 4) | (adr & 0xf); ++ struct r8180_priv *priv = ieee80211_priv(dev); ++ ++ out = read_nic_word(dev, RFPinsOutput) & 0xfff3; ++ ++ write_nic_word(dev,RFPinsEnable, ++ (read_nic_word(dev,RFPinsEnable) | 0x7)); ++ ++ select = read_nic_word(dev, RFPinsSelect); ++ ++ write_nic_word(dev, RFPinsSelect, select | 0x7 | ++ ((priv->card_type == USB) ? 0 : SW_CONTROL_GPIO)); ++ ++// force_pci_posting(dev); ++// udelay(10); ++ ++ write_nic_word(dev, RFPinsOutput, out | BB_HOST_BANG_EN );//| 0x1fff); ++ ++// force_pci_posting(dev); ++// udelay(2); ++ ++ write_nic_word(dev, RFPinsOutput, out); ++ ++// force_pci_posting(dev); ++// udelay(10); ++ ++ ++ for(i=15; i>=0;i--){ ++ ++ bit = (bangdata & (1<<i)) >> i; ++ ++ write_nic_word(dev, RFPinsOutput, bit | out); ++ ++ write_nic_word(dev, RFPinsOutput, bit | out | BB_HOST_BANG_CLK); ++ write_nic_word(dev, RFPinsOutput, bit | out | BB_HOST_BANG_CLK); ++ ++ i--; ++ bit = (bangdata & (1<<i)) >> i; ++ ++ write_nic_word(dev, RFPinsOutput, bit | out | BB_HOST_BANG_CLK); ++ write_nic_word(dev, RFPinsOutput, bit | out | BB_HOST_BANG_CLK); ++ ++ write_nic_word(dev, RFPinsOutput, bit | out); ++ ++ } ++ ++ write_nic_word(dev, RFPinsOutput, out | BB_HOST_BANG_EN); ++ ++// force_pci_posting(dev); ++// udelay(10); ++ ++ write_nic_word(dev, RFPinsOutput, out | ++ ((priv->card_type == USB) ? 4 : BB_HOST_BANG_EN)); ++ ++ write_nic_word(dev, RFPinsSelect, select | ++ ((priv->card_type == USB) ? 0 : SW_CONTROL_GPIO)); ++ ++ if(priv->card_type == USB) ++ ;// msleep(2); ++ else ++// rtl8185_rf_pins_enable(dev); ++#endif ++} ++ ++ ++void write_rtl8225_patch(struct net_device *dev, u8 adr, u16 data) ++{ ++ ++ int i; ++ u16 out,select; ++ u8 bit; ++ u32 bangdata = (data << 4) | (adr & 0xf); ++ struct r8180_priv *priv = ieee80211_priv(dev); ++ ++ out = read_nic_word(dev, RFPinsOutput) & 0xfff3; ++ ++ write_nic_word(dev,RFPinsEnable, ++ (read_nic_word(dev,RFPinsEnable) | 0x7)); ++ ++ select = read_nic_word(dev, RFPinsSelect); ++ ++ write_nic_word(dev, RFPinsSelect, select | 0x7 | ++ ((priv->card_type == USB) ? 0 : SW_CONTROL_GPIO)); ++ ++ force_pci_posting(dev); ++ udelay(10); ++ ++ write_nic_word(dev, RFPinsOutput, out | BB_HOST_BANG_EN );//| 0x1fff); ++ ++ force_pci_posting(dev); ++ udelay(2); ++ ++ write_nic_word(dev, RFPinsOutput, out); ++ ++ force_pci_posting(dev); ++ udelay(10); ++ ++ for(i=15; i>=0;i--){ ++ ++ bit = (bangdata & (1<<i)) >> i; ++ ++ write_nic_word(dev, RFPinsOutput, bit | out); ++ ++ write_nic_word(dev, RFPinsOutput, bit | out | BB_HOST_BANG_CLK); ++ write_nic_word(dev, RFPinsOutput, bit | out | BB_HOST_BANG_CLK); ++ ++ i--; ++ bit = (bangdata & (1<<i)) >> i; ++ ++ write_nic_word(dev, RFPinsOutput, bit | out | BB_HOST_BANG_CLK); ++ write_nic_word(dev, RFPinsOutput, bit | out | BB_HOST_BANG_CLK); ++ ++ write_nic_word(dev, RFPinsOutput, bit | out); ++ ++ } ++ ++ write_nic_word(dev, RFPinsOutput, out | BB_HOST_BANG_EN); ++ ++ force_pci_posting(dev); ++ udelay(10); ++ ++ write_nic_word(dev, RFPinsOutput, out | ++ ((priv->card_type == USB) ? 4 : BB_HOST_BANG_EN)); ++ ++ write_nic_word(dev, RFPinsSelect, select | ++ ((priv->card_type == USB) ? 0 : SW_CONTROL_GPIO)); ++ ++ if(priv->card_type == USB) ++ mdelay(2); ++ else ++ rtl8185_rf_pins_enable(dev); ++ ++} ++ ++void rtl8225_rf_close(struct net_device *dev) ++{ ++ write_rtl8225(dev, 0x4, 0x1f); ++ ++ force_pci_posting(dev); ++ mdelay(1); ++ ++ rtl8180_set_anaparam(dev, RTL8225_ANAPARAM_OFF); ++ rtl8185_set_anaparam2(dev, RTL8225_ANAPARAM2_OFF); ++} ++ ++#ifdef ENABLE_DOT11D ++// ++// Description: ++// Map dBm into Tx power index according to ++// current HW model, for example, RF and PA, and ++// current wireless mode. ++// ++s8 ++DbmToTxPwrIdx( ++ struct r8180_priv *priv, ++ WIRELESS_MODE WirelessMode, ++ s32 PowerInDbm ++ ) ++{ ++ bool bUseDefault = true; ++ s8 TxPwrIdx = 0; ++ ++#ifdef CONFIG_RTL818X_S ++ // ++ // 071011, SD3 SY: ++ // OFDM Power in dBm = Index * 0.5 + 0 ++ // CCK Power in dBm = Index * 0.25 + 13 ++ // ++ if(priv->card_8185 >= VERSION_8187S_B) ++ { ++ s32 tmp = 0; ++ ++ if(WirelessMode == WIRELESS_MODE_G) ++ { ++ bUseDefault = false; ++ tmp = (2 * PowerInDbm); ++ ++ if(tmp < 0) ++ TxPwrIdx = 0; ++ else if(tmp > 40) // 40 means 20 dBm. ++ TxPwrIdx = 40; ++ else ++ TxPwrIdx = (s8)tmp; ++ } ++ else if(WirelessMode == WIRELESS_MODE_B) ++ { ++ bUseDefault = false; ++ tmp = (4 * PowerInDbm) - 52; ++ ++ if(tmp < 0) ++ TxPwrIdx = 0; ++ else if(tmp > 28) // 28 means 20 dBm. ++ TxPwrIdx = 28; ++ else ++ TxPwrIdx = (s8)tmp; ++ } ++ } ++#endif ++ ++ // ++ // TRUE if we want to use a default implementation. ++ // We shall set it to FALSE when we have exact translation formular ++ // for target IC. 070622, by rcnjko. ++ // ++ if(bUseDefault) ++ { ++ if(PowerInDbm < 0) ++ TxPwrIdx = 0; ++ else if(PowerInDbm > 35) ++ TxPwrIdx = 35; ++ else ++ TxPwrIdx = (u8)PowerInDbm; ++ } ++ ++ return TxPwrIdx; ++} ++#endif ++ ++ ++short rtl8225_rf_set_sens(struct net_device *dev, short sens) ++{ ++ if (sens <0 || sens > 6) return -1; ++ ++ if(sens > 4) ++ write_rtl8225(dev, 0x0c, 0x850); ++ else ++ write_rtl8225(dev, 0x0c, 0x50); ++ ++ sens= 6-sens; ++ rtl8225_set_gain(dev, sens); ++ ++ write_phy_cck(dev, 0x41, rtl8225_threshold[sens]); ++ return 0; ++ ++} ++ ++void rtl8225_SetTXPowerLevel(struct net_device *dev, short ch) ++{ ++ struct r8180_priv *priv = ieee80211_priv(dev); ++ ++ int GainIdx; ++ int GainSetting; ++ int i; ++ u8 power; ++ u8 *cck_power_table; ++ u8 max_cck_power_level; ++ u8 max_ofdm_power_level; ++ u8 min_ofdm_power_level; ++ u8 cck_power_level = 0xff & priv->chtxpwr[ch]; ++ u8 ofdm_power_level = 0xff & priv->chtxpwr_ofdm[ch]; ++ ++#ifdef ENABLE_DOT11D ++ if(IS_DOT11D_ENABLE(priv->ieee80211) && ++ IS_DOT11D_STATE_DONE(priv->ieee80211) ) ++ { ++ //PRT_DOT11D_INFO pDot11dInfo = GET_DOT11D_INFO(priv->ieee80211); ++ u8 MaxTxPwrInDbm = DOT11D_GetMaxTxPwrInDbm(priv->ieee80211, ch); ++ u8 CckMaxPwrIdx = DbmToTxPwrIdx(priv, WIRELESS_MODE_B, MaxTxPwrInDbm); ++ u8 OfdmMaxPwrIdx = DbmToTxPwrIdx(priv, WIRELESS_MODE_G, MaxTxPwrInDbm); ++ ++ //printk("Max Tx Power dBm (%d) => CCK Tx power index : %d, OFDM Tx power index: %d\n", MaxTxPwrInDbm, CckMaxPwrIdx, OfdmMaxPwrIdx); ++ ++ //printk("EEPROM channel(%d) => CCK Tx power index: %d, OFDM Tx power index: %d\n", ++ // ch, cck_power_level, ofdm_power_level); ++ ++ if(cck_power_level > CckMaxPwrIdx) ++ cck_power_level = CckMaxPwrIdx; ++ if(ofdm_power_level > OfdmMaxPwrIdx) ++ ofdm_power_level = OfdmMaxPwrIdx; ++ } ++ ++ //priv->CurrentCckTxPwrIdx = cck_power_level; ++ //priv->CurrentOfdmTxPwrIdx = ofdm_power_level; ++#endif ++ ++ ++ if(priv->card_type == USB){ ++ max_cck_power_level = 11; ++ max_ofdm_power_level = 25; // 12 -> 25 ++ min_ofdm_power_level = 10; ++ }else{ ++ max_cck_power_level = 35; ++ max_ofdm_power_level = 35; ++ min_ofdm_power_level = 0; ++ } ++ if( priv->TrSwitchState == TR_SW_TX ) ++ { ++ printk("SetTxPowerLevel8187(): Origianl OFDM Tx power level %d\n", ofdm_power_level); ++ ofdm_power_level -= GetTxOfdmHighPowerBias(dev); ++ cck_power_level -= GetTxCckHighPowerBias(dev); ++ printk("SetTxPowerLevel8187(): Adjusted OFDM Tx power level %d for we are in High Power state\n", ++ ofdm_power_level); ++ printk("SetTxPowerLevel8187(): Adjusted CCK Tx power level %d for we are in High Power state\n", ++ cck_power_level); ++ } ++ ++ ++ ++ /* CCK power setting */ ++ if(cck_power_level > max_cck_power_level) ++ cck_power_level = max_cck_power_level; ++ GainIdx=cck_power_level % 6; ++ GainSetting=cck_power_level / 6; ++ ++ if(ch == 14) ++ cck_power_table = rtl8225_tx_power_cck_ch14; ++ else ++ cck_power_table = rtl8225_tx_power_cck; ++ ++// if(priv->card_8185 == 1 && priv->card_8185_Bversion ){ ++ /*Ver B*/ ++// write_nic_byte(dev, TX_GAIN_CCK, rtl8225_tx_gain_cck_ofdm[GainSetting]); ++// }else{ ++ /*Ver C - D */ ++ write_nic_byte(dev, CCK_TXAGC, rtl8225_tx_gain_cck_ofdm[GainSetting]>>1); ++// } ++ ++ for(i=0;i<8;i++){ ++ ++ power = cck_power_table[GainIdx * 8 + i]; ++ write_phy_cck(dev, 0x44 + i, power); ++ } ++ ++ /* FIXME Is this delay really needeed ? */ ++ force_pci_posting(dev); ++ mdelay(1); ++ ++ /* OFDM power setting */ ++// Old: ++// if(ofdm_power_level > max_ofdm_power_level) ++// ofdm_power_level = 35; ++// ofdm_power_level += min_ofdm_power_level; ++// Latest: ++ if(ofdm_power_level > (max_ofdm_power_level - min_ofdm_power_level)) ++ ofdm_power_level = max_ofdm_power_level; ++ else ++ ofdm_power_level += min_ofdm_power_level; ++ if(ofdm_power_level > 35) ++ ofdm_power_level = 35; ++// ++ ++ GainIdx=ofdm_power_level % 6; ++ GainSetting=ofdm_power_level / 6; ++#if 1 ++// if(priv->card_type == USB){ ++ rtl8185_set_anaparam2(dev,RTL8225_ANAPARAM2_ON); ++ ++ write_phy_ofdm(dev,2,0x42); ++ write_phy_ofdm(dev,6,0); ++ write_phy_ofdm(dev,8,0); ++// } ++#endif ++// if(priv->card_8185 == 1 && priv->card_8185_Bversion){ ++// /*Ver B*/ ++// write_nic_byte(dev, TX_GAIN_OFDM, rtl8225_tx_gain_cck_ofdm[GainSetting]); ++// }else{ ++ /*Ver C - D */ ++ write_nic_byte(dev, OFDM_TXAGC, rtl8225_tx_gain_cck_ofdm[GainSetting]>>1); ++// } ++ ++ ++ power = rtl8225_tx_power_ofdm[GainIdx]; ++ ++ write_phy_ofdm(dev, 0x5, power); ++ write_phy_ofdm(dev, 0x7, power); ++ ++ force_pci_posting(dev); ++ mdelay(1); ++ //write_nic_byte(dev, TX_AGC_CONTROL,4); ++} ++ ++void rtl8225_rf_set_chan(struct net_device *dev, short ch) ++{ ++ struct r8180_priv *priv = ieee80211_priv(dev); ++ short gset = (priv->ieee80211->state == IEEE80211_LINKED && ++ ieee80211_is_54g(priv->ieee80211->current_network)) || ++ priv->ieee80211->iw_mode == IW_MODE_MONITOR; ++ int eifs_addr; ++ ++ if(NIC_8187 == priv->card_8187) { ++ eifs_addr = EIFS_8187; ++ } else { ++ eifs_addr = EIFS_8187B; ++ } ++ ++#ifdef ENABLE_DOT11D ++ if(!IsLegalChannel(priv->ieee80211, ch) ) ++ { ++ printk("channel(%d). is invalide\n", ch); ++ return; ++ } ++#endif ++ ++ rtl8225_SetTXPowerLevel(dev, ch); ++ ++ write_rtl8225(dev, 0x7, rtl8225_chan[ch]); ++ ++ force_pci_posting(dev); ++ mdelay(10); ++ ++ write_nic_byte(dev,SIFS,0x22);// SIFS: 0x22 ++ ++ if(gset) ++ write_nic_byte(dev,DIFS,20); //DIFS: 20 ++ else ++ write_nic_byte(dev,DIFS,0x24); //DIFS: 36 ++ ++ if(priv->ieee80211->state == IEEE80211_LINKED && ++ ieee80211_is_shortslot(priv->ieee80211->current_network)) ++ write_nic_byte(dev,SLOT,0x9); //SLOT: 9 ++ ++ else ++ write_nic_byte(dev,SLOT,0x14); //SLOT: 20 (0x14) ++ ++ ++ if(gset){ ++ write_nic_byte(dev,eifs_addr,91 - 20); // EIFS: 91 (0x5B) ++ write_nic_byte(dev,CW_VAL,0x73); //CW VALUE: 0x37 ++ //DMESG("using G net params"); ++ }else{ ++ write_nic_byte(dev,eifs_addr,91 - 0x24); // EIFS: 91 (0x5B) ++ write_nic_byte(dev,CW_VAL,0xa5); //CW VALUE: 0x37 ++ //DMESG("using B net params"); ++ } ++ ++ ++} ++ ++void rtl8225_host_pci_init(struct net_device *dev) ++{ ++ write_nic_word(dev, RFPinsOutput, 0x480); ++ ++ rtl8185_rf_pins_enable(dev); ++ ++ //if(priv->card_8185 == 2 && priv->enable_gpio0 ) /* version D */ ++ //write_nic_word(dev, RFPinsSelect, 0x88); ++ //else ++ write_nic_word(dev, RFPinsSelect, 0x88 | SW_CONTROL_GPIO); /* 0x488 | SW_CONTROL_GPIO */ ++ ++ write_nic_byte(dev, GP_ENABLE, 0); ++ ++ force_pci_posting(dev); ++ mdelay(200); ++ ++ write_nic_word(dev, GP_ENABLE, 0xff & (~(1<<6))); /* bit 6 is for RF on/off detection */ ++ ++ ++} ++ ++void rtl8225_host_usb_init(struct net_device *dev) ++{ ++ write_nic_byte(dev,RFPinsSelect+1,0); ++ ++ write_nic_byte(dev,GPIO,0); ++ ++ write_nic_byte_E(dev,0x53,read_nic_byte_E(dev,0x53) | (1<<7)); ++ ++ write_nic_byte(dev,RFPinsSelect+1,4); ++ ++ write_nic_byte(dev,GPIO,0x20); ++ ++ write_nic_byte(dev,GP_ENABLE,0); ++ ++ ++ /* Config BB & RF */ ++ write_nic_word(dev, RFPinsOutput, 0x80); ++ ++ write_nic_word(dev, RFPinsSelect, 0x80); ++ ++ write_nic_word(dev, RFPinsEnable, 0x80); ++ ++ ++ mdelay(100); ++ ++ mdelay(1000); ++ ++} ++ ++void rtl8225_rf_init(struct net_device *dev) ++{ ++ struct r8180_priv *priv = ieee80211_priv(dev); ++ int i; ++ short channel = 1; ++ u16 brsr; ++ int brsr_addr; ++ ++ if(NIC_8187 == priv->card_8187) { ++ brsr_addr = BRSR_8187; ++ } else { ++ brsr_addr = BRSR_8187B; ++ } ++ ++ ++ priv->chan = channel; ++ ++ rtl8180_set_anaparam(dev, RTL8225_ANAPARAM_ON); ++ ++ ++ if(priv->card_type == USB) ++ rtl8225_host_usb_init(dev); ++ else ++ rtl8225_host_pci_init(dev); ++ ++ write_nic_dword(dev, RF_TIMING, 0x000a8008); ++ ++ //brsr = read_nic_word(dev, BRSR); ++ brsr = read_nic_word(dev, brsr_addr); ++ ++ //write_nic_word(dev, BRSR, 0xffff); ++ write_nic_word(dev, brsr_addr, 0xffff); ++ ++ write_nic_dword(dev, RF_PARA, 0x100044); ++ ++ #if 1 //0->1 ++ rtl8180_set_mode(dev, EPROM_CMD_CONFIG); ++ write_nic_byte(dev, CONFIG3, 0x44); ++ rtl8180_set_mode(dev, EPROM_CMD_NORMAL); ++ #endif ++ ++ if(priv->card_type == USB){ ++ rtl8185_rf_pins_enable(dev); ++ ++ mdelay(1000); ++ } ++ ++ write_rtl8225(dev, 0x0, 0x67); mdelay(1); ++ ++ ++ write_rtl8225(dev, 0x1, 0xfe0); mdelay(1); ++ ++ write_rtl8225(dev, 0x2, 0x44d); mdelay(1); ++ ++ write_rtl8225(dev, 0x3, 0x441); mdelay(1); ++ ++ if(priv->card_type == USB) ++ write_rtl8225(dev, 0x4, 0x486); ++ else ++ write_rtl8225(dev, 0x4, 0x8be); ++ ++ mdelay(1); ++ ++ ++ /* version B & C */ ++ ++ if(priv->card_type == USB) ++ write_rtl8225(dev, 0x5, 0xbc0); ++ else if(priv->card_type == MINIPCI) ++ write_rtl8225(dev, 0x5, 0xbc0 + 3 +(6<<3)); ++ else ++ write_rtl8225(dev, 0x5, 0xbc0 + (6<<3)); ++ ++ mdelay(1); ++// } ++ ++ write_rtl8225(dev, 0x6, 0xae6); mdelay(1); ++ ++ write_rtl8225(dev, 0x7, ((priv->card_type == USB)? 0x82a : rtl8225_chan[channel])); mdelay(1); ++ ++ write_rtl8225(dev, 0x8, 0x1f); mdelay(1); ++ ++ write_rtl8225(dev, 0x9, 0x334); mdelay(1); ++ ++ write_rtl8225(dev, 0xa, 0xfd4); mdelay(1); ++ ++ write_rtl8225(dev, 0xb, 0x391); mdelay(1); ++ ++ write_rtl8225(dev, 0xc, 0x50); mdelay(1); ++ ++ ++ write_rtl8225(dev, 0xd, 0x6db); mdelay(1); ++ ++ write_rtl8225(dev, 0xe, 0x29); mdelay(1); ++ ++ write_rtl8225(dev, 0xf, 0x914); ++ ++ if(priv->card_type == USB){ ++ //force_pci_posting(dev); ++ mdelay(100); ++ } ++ ++ write_rtl8225(dev, 0x2, 0xc4d); ++ ++ if(priv->card_type == USB){ ++ // force_pci_posting(dev); ++ mdelay(200); ++ ++ write_rtl8225(dev, 0x2, 0x44d); ++ ++ // force_pci_posting(dev); ++ mdelay(100); ++ ++ }//End of if(priv->card_type == USB) ++ /* FIXME!! rtl8187 we have to check if calibrarion ++ * is successful and eventually cal. again (repeat ++ * the two write on reg 2) ++ */ ++ force_pci_posting(dev); ++ ++ mdelay(100); //200 for 8187 ++ ++ //if(priv->card_type != USB) /* maybe not needed even for 8185 */ ++// write_rtl8225(dev, 0x7, rtl8225_chan[channel]); ++ ++ write_rtl8225(dev, 0x0, 0x127); ++ ++ for(i=0;i<95;i++){ ++ write_rtl8225(dev, 0x1, (u8)(i+1)); ++ ++ /* version B & C & D*/ ++ ++ write_rtl8225(dev, 0x2, rtl8225bcd_rxgain[i]); ++ } ++ ++ write_rtl8225(dev, 0x0, 0x27); ++ ++ ++// //if(priv->card_type != USB){ ++// write_rtl8225(dev, 0x2, 0x44d); ++// write_rtl8225(dev, 0x7, rtl8225_chan[channel]); ++// write_rtl8225(dev, 0x2, 0x47d); ++// ++// force_pci_posting(dev); ++// mdelay(100); ++// ++// write_rtl8225(dev, 0x2, 0x44d); ++// //} ++ ++ write_rtl8225(dev, 0x0, 0x22f); ++ ++ if(priv->card_type != USB) ++ rtl8185_rf_pins_enable(dev); ++ ++ for(i=0;i<128;i++){ ++ write_phy_ofdm(dev, 0xb, rtl8225_agc[i]); ++ ++ mdelay(1); ++ write_phy_ofdm(dev, 0xa, (u8)i+ 0x80); ++ ++ mdelay(1); ++ } ++ ++ force_pci_posting(dev); ++ mdelay(1); ++ ++ write_phy_ofdm(dev, 0x0, 0x1); mdelay(1); ++ write_phy_ofdm(dev, 0x1, 0x2); mdelay(1); ++ write_phy_ofdm(dev, 0x2, ((priv->card_type == USB)? 0x42 : 0x62)); mdelay(1); ++ write_phy_ofdm(dev, 0x3, 0x0); mdelay(1); ++ write_phy_ofdm(dev, 0x4, 0x0); mdelay(1); ++ write_phy_ofdm(dev, 0x5, 0x0); mdelay(1); ++ write_phy_ofdm(dev, 0x6, 0x40); mdelay(1); ++ write_phy_ofdm(dev, 0x7, 0x0); mdelay(1); ++ write_phy_ofdm(dev, 0x8, 0x40); mdelay(1); ++ write_phy_ofdm(dev, 0x9, 0xfe); mdelay(1); ++ ++ /* ver C & D */ ++ write_phy_ofdm(dev, 0xa, 0x9); mdelay(1); ++ ++ //write_phy_ofdm(dev, 0x18, 0xef); ++ // } ++ //} ++ write_phy_ofdm(dev, 0xb, 0x80); mdelay(1); ++ ++ write_phy_ofdm(dev, 0xc, 0x1);mdelay(1); ++ ++ ++ //if(priv->card_type != USB) ++ //write_phy_ofdm(dev, 0xd, 0x33); // <> ++ ++ write_phy_ofdm(dev, 0xe, 0xd3);mdelay(1); ++ ++ write_phy_ofdm(dev, 0xf, 0x38);mdelay(1); ++/*ver D & 8187*/ ++// } ++ ++// if(priv->card_8185 == 1 && priv->card_8185_Bversion) ++// write_phy_ofdm(dev, 0x10, 0x04);/*ver B*/ ++// else ++ write_phy_ofdm(dev, 0x10, 0x84);mdelay(1); ++/*ver C & D & 8187*/ ++ ++ write_phy_ofdm(dev, 0x11, 0x06);mdelay(1); ++/*agc resp time 700*/ ++ ++ ++// if(priv->card_8185 == 2){ ++ /* Ver D & 8187*/ ++ write_phy_ofdm(dev, 0x12, 0x20);mdelay(1); ++ ++ write_phy_ofdm(dev, 0x13, 0x20);mdelay(1); ++ ++ write_phy_ofdm(dev, 0x14, 0x0); mdelay(1); ++ write_phy_ofdm(dev, 0x15, 0x40); mdelay(1); ++ write_phy_ofdm(dev, 0x16, 0x0); mdelay(1); ++ write_phy_ofdm(dev, 0x17, 0x40); mdelay(1); ++ ++// if (priv->card_type == USB) ++// write_phy_ofdm(dev, 0x18, 0xef); ++ ++ write_phy_ofdm(dev, 0x18, 0xef);mdelay(1); ++ ++ ++ write_phy_ofdm(dev, 0x19, 0x19); mdelay(1); ++ write_phy_ofdm(dev, 0x1a, 0x20); mdelay(1); ++ ++// if (priv->card_type != USB){ ++// if(priv->card_8185 == 1 && priv->card_8185_Bversion) ++// write_phy_ofdm(dev, 0x1b, 0x66); /* Ver B */ ++// else ++ write_phy_ofdm(dev, 0x1b, 0x76);mdelay(1); ++ /* Ver C & D */ //FIXME:MAYBE not needed ++// } ++ ++ write_phy_ofdm(dev, 0x1c, 0x4);mdelay(1); ++ ++ /*ver D & 8187*/ ++ write_phy_ofdm(dev, 0x1e, 0x95);mdelay(1); ++ ++ write_phy_ofdm(dev, 0x1f, 0x75); mdelay(1); ++ ++// } ++ ++ write_phy_ofdm(dev, 0x20, 0x1f);mdelay(1); ++ ++ write_phy_ofdm(dev, 0x21, 0x27);mdelay(1); ++ ++ write_phy_ofdm(dev, 0x22, 0x16);mdelay(1); ++ ++// if(priv->card_type != USB) ++ //write_phy_ofdm(dev, 0x23, 0x43); //FIXME maybe not needed // <> ++ ++ write_phy_ofdm(dev, 0x24, 0x46); mdelay(1); ++ write_phy_ofdm(dev, 0x25, 0x20); mdelay(1); ++ write_phy_ofdm(dev, 0x26, 0x90); mdelay(1); ++ write_phy_ofdm(dev, 0x27, 0x88); mdelay(1); ++/* Ver C & D & 8187*/ ++ ++ // <> Set init. gain to m74dBm. ++ ++ rtl8225_set_gain(dev,4); ++ /*write_phy_ofdm(dev, 0x0d, 0x43); mdelay(1); ++ write_phy_ofdm(dev, 0x1b, 0x76); mdelay(1); ++ write_phy_ofdm(dev, 0x1d, 0xc5); mdelay(1); ++ write_phy_ofdm(dev, 0x23, 0x78); mdelay(1); ++*/ ++ //if(priv->card_type == USB); ++ // rtl8225_set_gain_usb(dev, 1); /* FIXME this '2' is random */ ++ ++ write_phy_cck(dev, 0x0, 0x98); mdelay(1); ++ write_phy_cck(dev, 0x3, 0x20); mdelay(1); ++ write_phy_cck(dev, 0x4, 0x7e); mdelay(1); ++ write_phy_cck(dev, 0x5, 0x12); mdelay(1); ++ write_phy_cck(dev, 0x6, 0xfc); mdelay(1); ++ write_phy_cck(dev, 0x7, 0x78);mdelay(1); ++ /* Ver C & D & 8187*/ ++ ++ write_phy_cck(dev, 0x8, 0x2e);mdelay(1); ++ ++ write_phy_cck(dev, 0x10, ((priv->card_type == USB) ? 0x9b: 0x93)); mdelay(1); ++ write_phy_cck(dev, 0x11, 0x88); mdelay(1); ++ write_phy_cck(dev, 0x12, 0x47); mdelay(1); ++ write_phy_cck(dev, 0x13, 0xd0); /* Ver C & D & 8187*/ ++ ++ write_phy_cck(dev, 0x19, 0x0); ++ write_phy_cck(dev, 0x1a, 0xa0); ++ write_phy_cck(dev, 0x1b, 0x8); ++ write_phy_cck(dev, 0x40, 0x86); /* CCK Carrier Sense Threshold */ ++ ++ write_phy_cck(dev, 0x41, 0x8d);mdelay(1); ++ ++ ++ write_phy_cck(dev, 0x42, 0x15); mdelay(1); ++ write_phy_cck(dev, 0x43, 0x18); mdelay(1); ++ write_phy_cck(dev, 0x44, 0x1f); mdelay(1); ++ write_phy_cck(dev, 0x45, 0x1e); mdelay(1); ++ write_phy_cck(dev, 0x46, 0x1a); mdelay(1); ++ write_phy_cck(dev, 0x47, 0x15); mdelay(1); ++ write_phy_cck(dev, 0x48, 0x10); mdelay(1); ++ write_phy_cck(dev, 0x49, 0xa); mdelay(1); ++ write_phy_cck(dev, 0x4a, 0x5); mdelay(1); ++ write_phy_cck(dev, 0x4b, 0x2); mdelay(1); ++ write_phy_cck(dev, 0x4c, 0x5);mdelay(1); ++ ++ ++ write_nic_byte(dev, 0x5b, 0x0d); mdelay(1); ++ ++ ++ ++// <> ++// // TESTR 0xb 8187 ++// write_phy_cck(dev, 0x10, 0x93);// & 0xfb); ++// ++// //if(priv->card_type != USB){ ++// write_phy_ofdm(dev, 0x2, 0x62); ++// write_phy_ofdm(dev, 0x6, 0x0); ++// write_phy_ofdm(dev, 0x8, 0x0); ++// //} ++ ++ rtl8225_SetTXPowerLevel(dev, channel); ++ ++ write_phy_cck(dev, 0x10, 0x9b); mdelay(1); /* Rx ant A, 0xdb for B */ ++ write_phy_ofdm(dev, 0x26, 0x90); mdelay(1); /* Rx ant A, 0x10 for B */ ++ ++ rtl8185_tx_antenna(dev, 0x3); /* TX ant A, 0x0 for B */ ++ ++ /* switch to high-speed 3-wire ++ * last digit. 2 for both cck and ofdm ++ */ ++ if(priv->card_type == USB) ++ write_nic_dword(dev, 0x94, 0x3dc00002); ++ else{ ++ write_nic_dword(dev, 0x94, 0x15c00002); ++ rtl8185_rf_pins_enable(dev); ++ } ++ ++// if(priv->card_type != USB) ++// rtl8225_set_gain(dev, 4); /* FIXME this '1' is random */ // <> ++// rtl8225_set_mode(dev, 1); /* FIXME start in B mode */ // <> ++// ++// /* make sure is waken up! */ ++// write_rtl8225(dev,0x4, 0x9ff); ++// rtl8180_set_anaparam(dev, RTL8225_ANAPARAM_ON); ++// rtl8185_set_anaparam2(dev, RTL8225_ANAPARAM2_ON); ++ ++ rtl8225_rf_set_chan(dev, priv->chan); ++ ++ //write_nic_word(dev,BRSR,brsr); ++ ++} +diff -Nur linux-2.6.33/drivers/net/wireless/rtl8187b/r8180_rtl8225.h linux-lemote/drivers/net/wireless/rtl8187b/r8180_rtl8225.h +--- linux-2.6.33/drivers/net/wireless/rtl8187b/r8180_rtl8225.h 1970-01-01 01:00:00.000000000 +0100 ++++ linux-lemote/drivers/net/wireless/rtl8187b/r8180_rtl8225.h 2010-03-06 16:43:22.000000000 +0100 +@@ -0,0 +1,77 @@ ++/* ++ This is part of the rtl8180-sa2400 driver ++ released under the GPL (See file COPYING for details). ++ Copyright (c) 2005 Andrea Merello <andreamrl@tiscali.it> ++ ++ This files contains programming code for the rtl8225 ++ radio frontend. ++ ++ *Many* thanks to Realtek Corp. for their great support! ++ ++*/ ++ ++#ifndef RTL8225H ++#define RTL8225H ++ ++#include "r8187.h" ++ ++#define RTL8225_ANAPARAM_ON 0xa0000a59 ++ ++// FIXME: OFF ANAPARAM MIGHT BE WRONG! ++#define RTL8225_ANAPARAM_OFF 0xa00beb59 ++#define RTL8225_ANAPARAM2_OFF 0x840dec11 ++ ++#define RTL8225_ANAPARAM2_ON 0x860c7312 ++ ++void rtl8225_rf_init(struct net_device *dev); ++void rtl8225z2_rf_init(struct net_device *dev); ++void rtl8225z2_rf_set_chan(struct net_device *dev, short ch); ++short rtl8225_is_V_z2(struct net_device *dev); ++void rtl8225_rf_set_chan(struct net_device *dev,short ch); ++void rtl8225_rf_close(struct net_device *dev); ++short rtl8225_rf_set_sens(struct net_device *dev, short sens); ++void rtl8225_host_pci_init(struct net_device *dev); ++void rtl8225_host_usb_init(struct net_device *dev); ++void write_rtl8225(struct net_device *dev, u8 adr, u16 data); ++void rtl8225z2_rf_set_mode(struct net_device *dev) ; ++void rtl8185_rf_pins_enable(struct net_device *dev); ++void rtl8180_set_mode(struct net_device *dev,int mode); ++void UpdateInitialGain(struct net_device *dev); ++void UpdateCCKThreshold(struct net_device *dev); ++void rtl8225_SetTXPowerLevel(struct net_device *dev, short ch); ++void rtl8225z2_SetTXPowerLevel(struct net_device *dev, short ch); ++ ++#define RTL8225_RF_MAX_SENS 6 ++#define RTL8225_RF_DEF_SENS 4 ++ ++extern inline char GetTxOfdmHighPowerBias(struct net_device *dev) ++{ ++ // ++ // We should always adjust our Tx Power for 8187 and 8187B. ++ // It was ever recommended not to adjust Tx Power of 8187B with Atheros AP ++ // for throughput by David, but now we found it is not the issue to impact ++ // the Atheros's problem and also no adjustion for Tx Power will cause "low" ++ // throughput. By Bruce, 2007-07-03. ++ // ++ return 10; ++} ++ ++// ++// Description: ++// Return Tx power level to minus if we are in high power state. ++// ++// Note: ++// Adjust it according to RF if required. ++// ++extern inline char GetTxCckHighPowerBias(struct net_device *dev) ++{ ++ return 7; ++} ++ ++ ++ ++extern u8 rtl8225_agc[]; ++ ++extern u32 rtl8225_chan[]; ++ ++#endif +diff -Nur linux-2.6.33/drivers/net/wireless/rtl8187b/r8180_rtl8225z2.c linux-lemote/drivers/net/wireless/rtl8187b/r8180_rtl8225z2.c +--- linux-2.6.33/drivers/net/wireless/rtl8187b/r8180_rtl8225z2.c 1970-01-01 01:00:00.000000000 +0100 ++++ linux-lemote/drivers/net/wireless/rtl8187b/r8180_rtl8225z2.c 2010-03-06 16:43:22.000000000 +0100 +@@ -0,0 +1,2092 @@ ++/* ++ This is part of the rtl8180-sa2400 driver ++ released under the GPL (See file COPYING for details). ++ Copyright (c) 2005 Andrea Merello <andreamrl@tiscali.it> ++ ++ This files contains programming code for the rtl8225 ++ radio frontend. ++ ++ *Many* thanks to Realtek Corp. for their great support! ++ ++*/ ++ ++ ++ ++#include "r8180_hw.h" ++#include "r8180_rtl8225.h" ++#ifdef ENABLE_DOT11D ++#include "dot11d.h" ++#endif ++ ++//2005.11.16 ++u8 rtl8225z2_threshold[]={ ++ 0x8d, 0x8d, 0x8d, 0x8d, 0x9d, 0xad, 0xbd, ++}; ++ ++// 0xd 0x19 0x1b 0x21 ++u8 rtl8225z2_gain_bg[]={ ++ 0x23, 0x15, 0xa5, // -82-1dbm ++ 0x23, 0x15, 0xb5, // -82-2dbm ++ 0x23, 0x15, 0xc5, // -82-3dbm ++ 0x33, 0x15, 0xc5, // -78dbm ++ 0x43, 0x15, 0xc5, // -74dbm ++ 0x53, 0x15, 0xc5, // -70dbm ++ 0x63, 0x15, 0xc5, // -66dbm ++}; ++ ++u8 rtl8225z2_gain_a[]={ ++ 0x13,0x27,0x5a,//,0x37,// -82dbm ++ 0x23,0x23,0x58,//,0x37,// -82dbm ++ 0x33,0x1f,0x56,//,0x37,// -82dbm ++ 0x43,0x1b,0x54,//,0x37,// -78dbm ++ 0x53,0x17,0x51,//,0x37,// -74dbm ++ 0x63,0x24,0x4f,//,0x37,// -70dbm ++ 0x73,0x0f,0x4c,//,0x37,// -66dbm ++}; ++static u32 MAC_REG_TABLE[][3]={ ++ {0xf0, 0x32, 0000}, {0xf1, 0x32, 0000}, {0xf2, 0x00, 0000}, {0xf3, 0x00, 0000}, ++ {0xf4, 0x32, 0000}, {0xf5, 0x43, 0000}, {0xf6, 0x00, 0000}, {0xf7, 0x00, 0000}, ++ {0xf8, 0x46, 0000}, {0xf9, 0xa4, 0000}, {0xfa, 0x00, 0000}, {0xfb, 0x00, 0000}, ++ {0xfc, 0x96, 0000}, {0xfd, 0xa4, 0000}, {0xfe, 0x00, 0000}, {0xff, 0x00, 0000}, ++ ++ {0x58, 0x4b, 0001}, {0x59, 0x00, 0001}, {0x5a, 0x4b, 0001}, {0x5b, 0x00, 0001}, ++ {0x60, 0x4b, 0001}, {0x61, 0x09, 0001}, {0x62, 0x4b, 0001}, {0x63, 0x09, 0001}, ++ {0xce, 0x0f, 0001}, {0xcf, 0x00, 0001}, {0xe0, 0xff, 0001}, {0xe1, 0x0f, 0001}, ++ {0xe2, 0x00, 0001}, {0xf0, 0x4e, 0001}, {0xf1, 0x01, 0001}, {0xf2, 0x02, 0001}, ++ {0xf3, 0x03, 0001}, {0xf4, 0x04, 0001}, {0xf5, 0x05, 0001}, {0xf6, 0x06, 0001}, ++ {0xf7, 0x07, 0001}, {0xf8, 0x08, 0001}, ++ ++ {0x4e, 0x00, 0002}, {0x0c, 0x04, 0002}, {0x21, 0x61, 0002}, {0x22, 0x68, 0002}, ++ {0x23, 0x6f, 0002}, {0x24, 0x76, 0002}, {0x25, 0x7d, 0002}, {0x26, 0x84, 0002}, ++ {0x27, 0x8d, 0002}, {0x4d, 0x08, 0002}, {0x50, 0x05, 0002}, {0x51, 0xf5, 0002}, ++ {0x52, 0x04, 0002}, {0x53, 0xa0, 0002}, {0x54, 0x1f, 0002}, {0x55, 0x23, 0002}, ++ {0x56, 0x45, 0002}, {0x57, 0x67, 0002}, {0x58, 0x08, 0002}, {0x59, 0x08, 0002}, ++ {0x5a, 0x08, 0002}, {0x5b, 0x08, 0002}, {0x60, 0x08, 0002}, {0x61, 0x08, 0002}, ++ {0x62, 0x08, 0002}, {0x63, 0x08, 0002}, {0x64, 0xcf, 0002}, {0x72, 0x56, 0002}, ++ {0x73, 0x9a, 0002}, ++ ++ {0x34, 0xf0, 0000}, {0x35, 0x0f, 0000}, {0x5b, 0x40, 0000}, {0x84, 0x88, 0000}, ++ {0x85, 0x24, 0000}, {0x88, 0x54, 0000}, {0x8b, 0xb8, 0000}, {0x8c, 0x07, 0000}, ++ {0x8d, 0x00, 0000}, {0x94, 0x1b, 0000}, {0x95, 0x12, 0000}, {0x96, 0x00, 0000}, ++ {0x97, 0x06, 0000}, {0x9d, 0x1a, 0000}, {0x9f, 0x10, 0000}, {0xb4, 0x22, 0000}, ++ {0xbe, 0x80, 0000}, {0xdb, 0x00, 0000}, {0xee, 0x00, 0000}, {0x91, 0x01, 0000}, ++ //lzm mode 0x91 form 0x03->0x01 open GPIO BIT1, ++ //because Polling methord will rurn off Radio ++ //the first time when read GPI(0x92). ++ //because after 0x91:bit1 form 1->0, there will ++ //be time for 0x92:bit1 form 0->1 ++ ++ {0x4c, 0x00, 0002}, {0x9f, 0x00, 0003}, {0x8c, 0x01, 0000}, {0x8d, 0x10, 0000}, ++ {0x8e, 0x08, 0000}, {0x8f, 0x00, 0000} ++}; ++ ++static u8 ZEBRA_AGC[]={ ++ 0, ++ 0x5e,0x5e,0x5e,0x5e,0x5d,0x5b,0x59,0x57,0x55,0x53,0x51,0x4f,0x4d,0x4b,0x49,0x47, ++ 0x45,0x43,0x41,0x3f,0x3d,0x3b,0x39,0x37,0x35,0x33,0x31,0x2f,0x2d,0x2b,0x29,0x27, ++ 0x25,0x23,0x21,0x1f,0x1d,0x1b,0x19,0x17,0x15,0x13,0x11,0x0f,0x0d,0x0b,0x09,0x07, ++ 0x05,0x03,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01, ++ 0x19,0x19,0x19,0x019,0x19,0x19,0x19,0x19,0x19,0x20,0x21,0x22,0x23,0x24,0x25,0x26, ++ 0x26,0x27,0x27,0x28,0x28,0x29,0x2a,0x2a,0x2a,0x2b,0x2b,0x2b,0x2c,0x2c,0x2c,0x2d, ++ 0x2d,0x2d,0x2d,0x2e,0x2e,0x2e,0x2e,0x2f,0x2f,0x2f,0x30,0x30,0x31,0x31,0x31,0x31, ++ 0x31,0x31,0x31,0x31,0x31,0x31,0x31,0x31,0x31,0x31,0x31,0x31,0x31,0x31,0x31,0x31 ++}; ++ ++static u32 ZEBRA_RF_RX_GAIN_TABLE[]={ ++ 0, ++ 0x0400,0x0401,0x0402,0x0403,0x0404,0x0405,0x0408,0x0409, ++ 0x040a,0x040b,0x0502,0x0503,0x0504,0x0505,0x0540,0x0541, ++ 0x0542,0x0543,0x0544,0x0545,0x0580,0x0581,0x0582,0x0583, ++ 0x0584,0x0585,0x0588,0x0589,0x058a,0x058b,0x0643,0x0644, ++ 0x0645,0x0680,0x0681,0x0682,0x0683,0x0684,0x0685,0x0688, ++ 0x0689,0x068a,0x068b,0x068c,0x0742,0x0743,0x0744,0x0745, ++ 0x0780,0x0781,0x0782,0x0783,0x0784,0x0785,0x0788,0x0789, ++ 0x078a,0x078b,0x078c,0x078d,0x0790,0x0791,0x0792,0x0793, ++ 0x0794,0x0795,0x0798,0x0799,0x079a,0x079b,0x079c,0x079d, ++ 0x07a0,0x07a1,0x07a2,0x07a3,0x07a4,0x07a5,0x07a8,0x07a9, ++ 0x03aa,0x03ab,0x03ac,0x03ad,0x03b0,0x03b1,0x03b2,0x03b3, ++ 0x03b4,0x03b5,0x03b8,0x03b9,0x03ba,0x03bb,0x03bb ++}; ++ ++// Use the new SD3 given param, by shien chang, 2006.07.14 ++ ++static u8 OFDM_CONFIG[]={ ++ // 0x00 ++ 0x10, 0x0d, 0x01, 0x00, 0x14, 0xfb, 0xfb, 0x60, ++ 0x00, 0x60, 0x00, 0x00, 0x00, 0x5c, 0x00, 0x00, ++ ++ // 0x10 ++ 0x40, 0x00, 0x40, 0x00, 0x00, 0x00, 0xa8, 0x26, ++ 0x32, 0x33, 0x07, 0xa5, 0x6f, 0x55, 0xc8, 0xb3, ++ ++ // 0x20 ++ 0x0a, 0xe1, 0x2C, 0x8a, 0x86, 0x83, 0x34, 0x0f, ++ 0x4f, 0x24, 0x6f, 0xc2, 0x6b, 0x40, 0x80, 0x00, ++ ++ // 0x30 ++ 0xc0, 0xc1, 0x58, 0xf1, 0x00, 0xe4, 0x90, 0x3e, ++ 0x6d, 0x3c, 0xfb, 0x07//0xc7 ++ }; ++ ++//2005.11.16, ++u8 ZEBRA2_CCK_OFDM_GAIN_SETTING[]={ ++ 0x00,0x01,0x02,0x03,0x04,0x05, ++ 0x06,0x07,0x08,0x09,0x0a,0x0b, ++ 0x0c,0x0d,0x0e,0x0f,0x10,0x11, ++ 0x12,0x13,0x14,0x15,0x16,0x17, ++ 0x18,0x19,0x1a,0x1b,0x1c,0x1d, ++ 0x1e,0x1f,0x20,0x21,0x22,0x23, ++}; ++//- ++u16 rtl8225z2_rxgain[]={ ++ 0x0400, 0x0401, 0x0402, 0x0403, 0x0404, 0x0405, 0x0408, 0x0409, ++ 0x040a, 0x040b, 0x0502, 0x0503, 0x0504, 0x0505, 0x0540, 0x0541, ++ 0x0542, 0x0543, 0x0544, 0x0545, 0x0580, 0x0581, 0x0582, 0x0583, ++ 0x0584, 0x0585, 0x0588, 0x0589, 0x058a, 0x058b, 0x0643, 0x0644, ++ 0x0645, 0x0680, 0x0681, 0x0682, 0x0683, 0x0684, 0x0685, 0x0688, ++ 0x0689, 0x068a, 0x068b, 0x068c, 0x0742, 0x0743, 0x0744, 0x0745, ++ 0x0780, 0x0781, 0x0782, 0x0783, 0x0784, 0x0785, 0x0788, 0x0789, ++ 0x078a, 0x078b, 0x078c, 0x078d, 0x0790, 0x0791, 0x0792, 0x0793, ++ 0x0794, 0x0795, 0x0798, 0x0799, 0x079a, 0x079b, 0x079c, 0x079d, ++ 0x07a0, 0x07a1, 0x07a2, 0x07a3, 0x07a4, 0x07a5, 0x07a8, 0x07a9, ++ 0x03aa, 0x03ab, 0x03ac, 0x03ad, 0x03b0, 0x03b1, 0x03b2, 0x03b3, ++ 0x03b4, 0x03b5, 0x03b8, 0x03b9, 0x03ba, 0x03bb, 0x03bb ++ ++}; ++ ++ ++/* ++ from 0 to 0x23 ++u8 rtl8225_tx_gain_cck_ofdm[]={ ++ 0x02,0x06,0x0e,0x1e,0x3e,0x7e ++}; ++*/ ++ ++//- ++u8 rtl8225z2_tx_power_ofdm[]={ ++ 0x42,0x00,0x40,0x00,0x40 ++}; ++ ++ ++//- ++u8 rtl8225z2_tx_power_cck_ch14[]={ ++ 0x36,0x35,0x2e,0x1b,0x00,0x00,0x00,0x00, ++ 0x30, 0x2f, 0x29, 0x15, 0x00, 0x00, 0x00, 0x00, ++ 0x30, 0x2f, 0x29, 0x15, 0x00, 0x00, 0x00, 0x00, ++ 0x30, 0x2f, 0x29, 0x15, 0x00, 0x00, 0x00, 0x00, ++}; ++ ++ ++//- ++u8 rtl8225z2_tx_power_cck[]={ ++ 0x36,0x35,0x2e,0x25,0x1c,0x12,0x09,0x04, ++ 0x30, 0x2f, 0x29, 0x21, 0x19, 0x10, 0x08, 0x03, ++ 0x2b, 0x2a, 0x25, 0x1e, 0x16, 0x0e, 0x07, 0x03, ++ 0x26, 0x25, 0x21, 0x1b, 0x14, 0x0d, 0x06, 0x03 ++}; ++ ++#ifdef ENABLE_DOT11D ++// ++// Description: ++// Map dBm into Tx power index according to ++// current HW model, for example, RF and PA, and ++// current wireless mode. ++// ++s8 ++rtl8187B_DbmToTxPwrIdx( ++ struct r8180_priv *priv, ++ WIRELESS_MODE WirelessMode, ++ s32 PowerInDbm ++ ) ++{ ++ bool bUseDefault = true; ++ s8 TxPwrIdx = 0; ++ ++#ifdef CONFIG_RTL818X_S ++ // ++ // 071011, SD3 SY: ++ // OFDM Power in dBm = Index * 0.5 + 0 ++ // CCK Power in dBm = Index * 0.25 + 13 ++ // ++ if(priv->card_8185 >= VERSION_8187S_B) ++ { ++ s32 tmp = 0; ++ ++ if(WirelessMode == WIRELESS_MODE_G) ++ { ++ bUseDefault = false; ++ tmp = (2 * PowerInDbm); ++ ++ if(tmp < 0) ++ TxPwrIdx = 0; ++ else if(tmp > 40) // 40 means 20 dBm. ++ TxPwrIdx = 40; ++ else ++ TxPwrIdx = (s8)tmp; ++ } ++ else if(WirelessMode == WIRELESS_MODE_B) ++ { ++ bUseDefault = false; ++ tmp = (4 * PowerInDbm) - 52; ++ ++ if(tmp < 0) ++ TxPwrIdx = 0; ++ else if(tmp > 28) // 28 means 20 dBm. ++ TxPwrIdx = 28; ++ else ++ TxPwrIdx = (s8)tmp; ++ } ++ } ++#endif ++ ++ // ++ // TRUE if we want to use a default implementation. ++ // We shall set it to FALSE when we have exact translation formular ++ // for target IC. 070622, by rcnjko. ++ // ++ if(bUseDefault) ++ { ++ if(PowerInDbm < 0) ++ TxPwrIdx = 0; ++ else if(PowerInDbm > 35) ++ TxPwrIdx = 35; ++ else ++ TxPwrIdx = (u8)PowerInDbm; ++ } ++ ++ return TxPwrIdx; ++} ++#endif ++ ++ ++void rtl8225z2_set_gain(struct net_device *dev, short gain) ++{ ++ u8* rtl8225_gain; ++ struct r8180_priv *priv = ieee80211_priv(dev); ++ ++ u8 mode = priv->ieee80211->mode; ++ ++ if(mode == IEEE_B || mode == IEEE_G) ++ rtl8225_gain = rtl8225z2_gain_bg; ++ else ++ rtl8225_gain = rtl8225z2_gain_a; ++ ++ //write_phy_ofdm(dev, 0x0d, rtl8225_gain[gain * 3]); ++ //write_phy_ofdm(dev, 0x19, rtl8225_gain[gain * 3 + 1]); ++ //write_phy_ofdm(dev, 0x1b, rtl8225_gain[gain * 3 + 2]); ++ //2005.11.17, by ch-hsu ++ write_phy_ofdm(dev, 0x0b, rtl8225_gain[gain * 3]); ++ write_phy_ofdm(dev, 0x1b, rtl8225_gain[gain * 3 + 1]); ++ write_phy_ofdm(dev, 0x1d, rtl8225_gain[gain * 3 + 2]); ++ write_phy_ofdm(dev, 0x21, 0x37); ++ ++} ++ ++u32 read_rtl8225(struct net_device *dev, u8 adr) ++{ ++ u32 data2Write = ((u32)(adr & 0x1f)) << 27; ++ u32 dataRead; ++ u32 mask; ++ u16 oval,oval2,oval3,tmp; ++// ThreeWireReg twreg; ++// ThreeWireReg tdata; ++ int i; ++ short bit, rw; ++ ++ u8 wLength = 6; ++ u8 rLength = 12; ++ u8 low2high = 0; ++ ++ oval = read_nic_word(dev, RFPinsOutput); ++ oval2 = read_nic_word(dev, RFPinsEnable); ++ oval3 = read_nic_word(dev, RFPinsSelect); ++ write_nic_word(dev, RFPinsEnable, (oval2|0xf)); ++ write_nic_word(dev, RFPinsSelect, (oval3|0xf)); ++ ++ dataRead = 0; ++ ++ oval &= ~0xf; ++ ++ write_nic_word(dev, RFPinsOutput, oval | BB_HOST_BANG_EN ); udelay(4); ++ ++ write_nic_word(dev, RFPinsOutput, oval ); udelay(5); ++ ++ rw = 0; ++ ++ mask = (low2high) ? 0x01 : (((u32)0x01)<<(32-1)); ++ for(i = 0; i < wLength/2; i++) ++ { ++ bit = ((data2Write&mask) != 0) ? 1 : 0; ++ write_nic_word(dev, RFPinsOutput, bit|oval | rw); udelay(1); ++ ++ write_nic_word(dev, RFPinsOutput, bit|oval | BB_HOST_BANG_CLK | rw); udelay(2); ++ write_nic_word(dev, RFPinsOutput, bit|oval | BB_HOST_BANG_CLK | rw); udelay(2); ++ ++ mask = (low2high) ? (mask<<1): (mask>>1); ++ ++ if(i == 2) ++ { ++ rw = BB_HOST_BANG_RW; ++ write_nic_word(dev, RFPinsOutput, bit|oval | BB_HOST_BANG_CLK | rw); udelay(2); ++ write_nic_word(dev, RFPinsOutput, bit|oval | rw); udelay(2); ++ break; ++ } ++ ++ bit = ((data2Write&mask) != 0) ? 1: 0; ++ ++ write_nic_word(dev, RFPinsOutput, oval|bit|rw| BB_HOST_BANG_CLK); udelay(2); ++ write_nic_word(dev, RFPinsOutput, oval|bit|rw| BB_HOST_BANG_CLK); udelay(2); ++ ++ write_nic_word(dev, RFPinsOutput, oval| bit |rw); udelay(1); ++ ++ mask = (low2high) ? (mask<<1) : (mask>>1); ++ } ++ ++ //twreg.struc.clk = 0; ++ //twreg.struc.data = 0; ++ write_nic_word(dev, RFPinsOutput, rw|oval); udelay(2); ++ mask = (low2high) ? 0x01 : (((u32)0x01) << (12-1)); ++ ++ // We must set data pin to HW controled, otherwise RF can't driver it and ++ // value RF register won't be able to read back properly. 2006.06.13, by rcnjko. ++ write_nic_word(dev, RFPinsEnable,((oval2|0xe) & (~0x01))); ++ ++ for(i = 0; i < rLength; i++) ++ { ++ write_nic_word(dev, RFPinsOutput, rw|oval); udelay(1); ++ ++ write_nic_word(dev, RFPinsOutput, rw|oval|BB_HOST_BANG_CLK); udelay(2); ++ write_nic_word(dev, RFPinsOutput, rw|oval|BB_HOST_BANG_CLK); udelay(2); ++ write_nic_word(dev, RFPinsOutput, rw|oval|BB_HOST_BANG_CLK); udelay(2); ++ tmp = read_nic_word(dev, RFPinsInput); ++ ++ dataRead |= (tmp & BB_HOST_BANG_CLK ? mask : 0); ++ ++ write_nic_word(dev, RFPinsOutput, (rw|oval)); udelay(2); ++ ++ mask = (low2high) ? (mask<<1) : (mask>>1); ++ } ++ ++ write_nic_word(dev, RFPinsOutput, BB_HOST_BANG_EN|BB_HOST_BANG_RW|oval); udelay(2); ++ ++ write_nic_word(dev, RFPinsEnable, oval2); ++ write_nic_word(dev, RFPinsSelect, oval3); // Set To SW Switch ++ write_nic_word(dev, RFPinsOutput, 0x3a0); ++ ++ return dataRead; ++ ++} ++short rtl8225_is_V_z2(struct net_device *dev) ++{ ++ short vz2 = 1; ++ //set VCO-PDN pin ++// printk("%s()\n", __FUNCTION__); ++ write_nic_word(dev, RFPinsOutput, 0x0080); ++ write_nic_word(dev, RFPinsSelect, 0x0080); ++ write_nic_word(dev, RFPinsEnable, 0x0080); ++ ++ //lzm mod for up take too long time 20081201 ++ //mdelay(100); ++ //mdelay(1000); ++ ++ /* sw to reg pg 1 */ ++ write_rtl8225(dev, 0, 0x1b7); ++ /* reg 8 pg 1 = 23*/ ++ if( read_rtl8225(dev, 8) != 0x588) ++ vz2 = 0; ++ ++ else /* reg 9 pg 1 = 24 */ ++ if( read_rtl8225(dev, 9) != 0x700) ++ vz2 = 0; ++ ++ /* sw back to pg 0 */ ++ write_rtl8225(dev, 0, 0xb7); ++ ++ return vz2; ++ ++} ++ ++void rtl8225z2_SetTXPowerLevel(struct net_device *dev, short ch) ++{ ++ struct r8180_priv *priv = ieee80211_priv(dev); ++ ++// int GainIdx; ++// int GainSetting; ++ int i; ++ u8 power; ++ u8 *cck_power_table; ++ u8 max_cck_power_level; ++ u8 min_cck_power_level; ++ u8 max_ofdm_power_level; ++ u8 min_ofdm_power_level; ++ s8 cck_power_level = 0xff & priv->chtxpwr[ch]; ++ s8 ofdm_power_level = 0xff & priv->chtxpwr_ofdm[ch]; ++ u8 hw_version = priv->card_8187_Bversion; ++ ++#ifdef ENABLE_DOT11D ++ if(IS_DOT11D_ENABLE(priv->ieee80211) && ++ IS_DOT11D_STATE_DONE(priv->ieee80211) ) ++ { ++ //PRT_DOT11D_INFO pDot11dInfo = GET_DOT11D_INFO(priv->ieee80211); ++ u8 MaxTxPwrInDbm = DOT11D_GetMaxTxPwrInDbm(priv->ieee80211, ch); ++ u8 CckMaxPwrIdx = rtl8187B_DbmToTxPwrIdx(priv, WIRELESS_MODE_B, MaxTxPwrInDbm); ++ u8 OfdmMaxPwrIdx = rtl8187B_DbmToTxPwrIdx(priv, WIRELESS_MODE_G, MaxTxPwrInDbm); ++ ++ //printk("Max Tx Power dBm (%d) => CCK Tx power index : %d, OFDM Tx power index: %d\n", MaxTxPwrInDbm, CckMaxPwrIdx, OfdmMaxPwrIdx); ++ ++ //printk("EEPROM channel(%d) => CCK Tx power index: %d, OFDM Tx power index: %d\n", ++ // ch, cck_power_level, ofdm_power_level); ++ ++ if(cck_power_level > CckMaxPwrIdx) ++ cck_power_level = CckMaxPwrIdx; ++ if(ofdm_power_level > OfdmMaxPwrIdx) ++ ofdm_power_level = OfdmMaxPwrIdx; ++ } ++ ++ //priv->CurrentCckTxPwrIdx = cck_power_level; ++ //priv->CurrentOfdmTxPwrIdx = ofdm_power_level; ++#endif ++ ++ if (NIC_8187B == priv->card_8187) ++ { ++ if (hw_version == VERSION_8187B_B) ++ { ++ min_cck_power_level = 0; ++ max_cck_power_level = 15; ++ min_ofdm_power_level = 2; ++ max_ofdm_power_level = 17; ++ }else ++ { ++ min_cck_power_level = 7; ++ max_cck_power_level = 22; ++ min_ofdm_power_level = 10; ++ max_ofdm_power_level = 25; ++ } ++ ++ if( priv->TrSwitchState == TR_SW_TX ) ++ { ++ //printk("SetTxPowerLevel8187(): Origianl OFDM Tx power level %d, adjust value = %d\n", ofdm_power_level,GetTxOfdmHighPowerBias(dev)); ++ ofdm_power_level -= GetTxOfdmHighPowerBias(dev); ++ cck_power_level -= GetTxCckHighPowerBias(dev); ++ //printk("SetTxPowerLevel8187(): Adjusted OFDM Tx power level %d for we are in High Power state\n", ++ // ofdm_power_level); ++ //printk("SetTxPowerLevel8187(): Adjusted CCK Tx power level %d for we are in High Power state\n", ++ // cck_power_level); ++ } ++ /* CCK power setting */ ++ if(cck_power_level > (max_cck_power_level -min_cck_power_level)) ++ cck_power_level = max_cck_power_level; ++ else ++ cck_power_level += min_cck_power_level; ++ cck_power_level += priv->cck_txpwr_base; ++ ++ if(cck_power_level > 35) ++ cck_power_level = 35; ++ if(cck_power_level < 0) ++ cck_power_level = 0; ++ ++ if(ch == 14) ++ cck_power_table = rtl8225z2_tx_power_cck_ch14; ++ else ++ cck_power_table = rtl8225z2_tx_power_cck; ++ if (hw_version == VERSION_8187B_B) ++ { ++ if (cck_power_level <= 6){ ++ } ++ else if (cck_power_level <=11){ ++ cck_power_table += 8; ++ } ++ else{ ++ cck_power_table += (8*2); ++ } ++ }else{ ++ if (cck_power_level<=5){ ++ }else if(cck_power_level<=11){ ++ cck_power_table += 8; ++ }else if(cck_power_level <= 17){ ++ cck_power_table += 8*2; ++ }else{ ++ cck_power_table += 8*3; ++ } ++ } ++ ++ ++ ++ for(i=0;i<8;i++){ ++ ++ power = cck_power_table[i]; ++ write_phy_cck(dev, 0x44 + i, power); ++ } ++ ++ //write_nic_byte(dev, TX_GAIN_CCK, power); ++ //2005.11.17, ++ write_nic_byte(dev, CCK_TXAGC, (ZEBRA2_CCK_OFDM_GAIN_SETTING[cck_power_level]*2)); ++ ++// force_pci_posting(dev); ++// msleep(1); ++//in windows the delay was del from 85 to 87, ++//here we mod to sleep, or The CPU occupany is too hight. LZM 31/10/2008 ++ ++ /* OFDM power setting */ ++ // Old: ++ // if(ofdm_power_level > max_ofdm_power_level) ++ // ofdm_power_level = 35; ++ // ofdm_power_level += min_ofdm_power_level; ++ // Latest: ++ if(ofdm_power_level > (max_ofdm_power_level - min_ofdm_power_level)) ++ ofdm_power_level = max_ofdm_power_level; ++ else ++ ofdm_power_level += min_ofdm_power_level; ++ ++ ofdm_power_level += priv->ofdm_txpwr_base; ++ ++ if(ofdm_power_level > 35) ++ ofdm_power_level = 35; ++ ++ if(ofdm_power_level < 0) ++ ofdm_power_level = 0; ++ write_nic_byte(dev, OFDM_TXAGC, ZEBRA2_CCK_OFDM_GAIN_SETTING[ofdm_power_level]*2); ++ ++ if (hw_version == VERSION_8187B_B) ++ { ++ if(ofdm_power_level<=11){ ++ write_phy_ofdm(dev, 0x87, 0x60); ++ write_phy_ofdm(dev, 0x89, 0x60); ++ } ++ else{ ++ write_phy_ofdm(dev, 0x87, 0x5c); ++ write_phy_ofdm(dev, 0x89, 0x5c); ++ } ++ }else{ ++ if(ofdm_power_level<=11){ ++ write_phy_ofdm(dev, 0x87, 0x5c); ++ write_phy_ofdm(dev, 0x89, 0x5c); ++ } ++ if(ofdm_power_level<=17){ ++ write_phy_ofdm(dev, 0x87, 0x54); ++ write_phy_ofdm(dev, 0x89, 0x54); ++ } ++ else{ ++ write_phy_ofdm(dev, 0x87, 0x50); ++ write_phy_ofdm(dev, 0x89, 0x50); ++ } ++ } ++// force_pci_posting(dev); ++// msleep(1); ++//in windows the delay was del from 85 to 87, ++//and here we mod to sleep, or The CPU occupany is too hight. LZM 31/10/2008 ++ }else if(NIC_8187 == priv->card_8187) { ++ min_cck_power_level = 0; ++ max_cck_power_level = 15; ++ min_ofdm_power_level = 10; ++ max_ofdm_power_level = 25; ++ if(cck_power_level > (max_cck_power_level -min_cck_power_level)) ++ cck_power_level = max_cck_power_level; ++ else ++ cck_power_level += min_cck_power_level; ++ cck_power_level += priv->cck_txpwr_base; ++ ++ if(cck_power_level > 35) ++ cck_power_level = 35; ++ ++ if(ch == 14) ++ cck_power_table = rtl8225z2_tx_power_cck_ch14; ++ else ++ cck_power_table = rtl8225z2_tx_power_cck; ++ for(i=0;i<8;i++){ ++ power = cck_power_table[i]; ++ write_phy_cck(dev, 0x44 + i, power); ++ } ++ ++ //write_nic_byte(dev, TX_GAIN_CCK, power); ++ //2005.11.17, ++ write_nic_byte(dev, CCK_TXAGC, ZEBRA2_CCK_OFDM_GAIN_SETTING[cck_power_level]); ++ ++// force_pci_posting(dev); ++// msleep(1); ++//in windows the delay was del from 85 to 87, ++//and here we mod to sleep, or The CPU occupany is too hight. LZM 31/10/2008 ++ if(ofdm_power_level > (max_ofdm_power_level - min_ofdm_power_level)) ++ ofdm_power_level = max_ofdm_power_level; ++ else ++ ofdm_power_level += min_ofdm_power_level; ++ ++ ofdm_power_level += priv->ofdm_txpwr_base; ++ ++ if(ofdm_power_level > 35) ++ ofdm_power_level = 35; ++ write_nic_byte(dev, OFDM_TXAGC, ZEBRA2_CCK_OFDM_GAIN_SETTING[ofdm_power_level]); ++ ++ rtl8185_set_anaparam2(dev,RTL8225_ANAPARAM2_ON); ++ ++ write_phy_ofdm(dev,2,0x42); ++ write_phy_ofdm(dev,5,0); ++ write_phy_ofdm(dev,6,0x40); ++ write_phy_ofdm(dev,7,0); ++ write_phy_ofdm(dev,8,0x40); ++ } ++ ++} ++ ++void rtl8225z2_rf_set_chan(struct net_device *dev, short ch) ++{ ++ struct r8180_priv *priv = ieee80211_priv(dev); ++ short gset = (priv->ieee80211->state == IEEE80211_LINKED && ++ ieee80211_is_54g(priv->ieee80211->current_network)) || ++ priv->ieee80211->iw_mode == IW_MODE_MONITOR; ++ int eifs_addr; ++ ++ down(&priv->set_chan_sem); ++ ++ if(NIC_8187 == priv->card_8187) { ++ eifs_addr = EIFS_8187; ++ } else { ++ eifs_addr = EIFS_8187B; ++ } ++ ++#ifdef ENABLE_DOT11D ++ if(!IsLegalChannel(priv->ieee80211, ch) ) ++ { ++ printk("channel(%d). is invalide\n", ch); ++ up(&priv->set_chan_sem); ++ return; ++ } ++#endif ++ //87B not do it FIXME ++ rtl8225z2_SetTXPowerLevel(dev, ch); ++ ++ //write_nic_byte(dev,0x7,(u8)rtl8225_chan[ch]); ++ write_rtl8225(dev, 0x7, rtl8225_chan[ch]); ++ ++ force_pci_posting(dev); ++ //mdelay(10); ++//in windows the delay was del from 85 to 87, ++//and here we mod to sleep, or The CPU occupany is too hight. LZM 31/10/2008 ++ if(NIC_8187 == priv->card_8187){ ++ write_nic_byte(dev,SIFS,0x22);// SIFS: 0x22 ++ ++ if(gset) ++ write_nic_byte(dev,DIFS,20); //DIFS: 20 ++ else ++ write_nic_byte(dev,DIFS,0x24); //DIFS: 36 ++ ++ if(priv->ieee80211->state == IEEE80211_LINKED && ++ ieee80211_is_shortslot(priv->ieee80211->current_network)) ++ write_nic_byte(dev,SLOT,0x9); //SLOT: 9 ++ ++ else ++ write_nic_byte(dev,SLOT,0x14); //SLOT: 20 (0x14) ++ ++ ++ if(gset){ ++ write_nic_byte(dev,eifs_addr,91 - 20); // EIFS: 91 (0x5B) ++ write_nic_byte(dev,CW_VAL,0x73); //CW VALUE: 0x37 ++ //DMESG("using G net params"); ++ }else{ ++ write_nic_byte(dev,eifs_addr,91 - 0x24); // EIFS: 91 (0x5B) ++ write_nic_byte(dev,CW_VAL,0xa5); //CW VALUE: 0x37 ++ //DMESG("using B net params"); ++ } ++ } ++ ++ else { ++#ifdef THOMAS_TURBO ++ if(priv->ieee80211->current_network.Turbo_Enable && priv->ieee80211->iw_mode == IW_MODE_INFRA){ ++ write_nic_word(dev,AC_VO_PARAM,0x5114); ++ write_nic_word(dev,AC_VI_PARAM,0x5114); ++ write_nic_word(dev,AC_BE_PARAM,0x5114); ++ write_nic_word(dev,AC_BK_PARAM,0x5114); ++ } else { ++ write_nic_word(dev,AC_VO_PARAM,0x731c); ++ write_nic_word(dev,AC_VI_PARAM,0x731c); ++ write_nic_word(dev,AC_BE_PARAM,0x731c); ++ write_nic_word(dev,AC_BK_PARAM,0x731c); ++ } ++#endif ++ } ++ ++ up(&priv->set_chan_sem); ++} ++void ++MacConfig_87BASIC_HardCode(struct net_device *dev) ++{ ++ //============================================================================ ++ // MACREG.TXT ++ //============================================================================ ++ int nLinesRead = 0; ++ u32 u4bRegOffset, u4bRegValue, u4bPageIndex; ++ int i; ++ ++ nLinesRead=(sizeof(MAC_REG_TABLE)/3)/4; ++ ++ for(i = 0; i < nLinesRead; i++) ++ { ++ u4bRegOffset=MAC_REG_TABLE[i][0]; ++ u4bRegValue=MAC_REG_TABLE[i][1]; ++ u4bPageIndex=MAC_REG_TABLE[i][2]; ++ ++ u4bRegOffset|= (u4bPageIndex << 8); ++ ++ write_nic_byte(dev, u4bRegOffset, (u8)u4bRegValue); ++ } ++ //============================================================================ ++} ++ ++static void MacConfig_87BASIC(struct net_device *dev) ++{ ++ MacConfig_87BASIC_HardCode(dev); ++ ++ //============================================================================ ++ ++ // Follow TID_AC_MAP of WMac. ++ //PlatformEFIOWrite2Byte(dev, TID_AC_MAP, 0xfa50); ++ write_nic_word(dev, TID_AC_MAP, 0xfa50); ++ ++ // Interrupt Migration, Jong suggested we use set 0x0000 first, 2005.12.14, by rcnjko. ++ write_nic_word(dev, INT_MIG, 0x0000); ++ ++ // Prevent TPC to cause CRC error. Added by Annie, 2006-06-10. ++ write_nic_dword(dev, 0x1F0, 0x00000000); ++ write_nic_dword(dev, 0x1F4, 0x00000000); ++ write_nic_byte(dev, 0x1F8, 0x00); ++ ++ // For WiFi 5.2.2.5 Atheros AP performance. Added by Annie, 2006-06-12. ++ // PlatformIOWrite4Byte(dev, RFTiming, 0x0008e00f); ++ // Asked for by SD3 CM Lin, 2006.06.27, by rcnjko. ++ write_nic_dword(dev, RFTiming, 0x00004001); ++ ++#ifdef TODO ++ // Asked for by Victor, for 87B B-cut Rx FIFO overflow bug, 2006.06.27, by rcnjko. ++ if(dev->NdisUsbDev.CardInfo.USBIsHigh == FALSE) ++ { ++ PlatformEFIOWrite1Byte(dev, 0x24E, 0x01); ++ } ++#endif ++} ++ ++ ++// ++// Description: ++// Initialize RFE and read Zebra2 version code. ++// ++// 2005-08-01, by Annie. ++// ++void ++SetupRFEInitialTiming(struct net_device* dev) ++{ ++ //u32 data8, data9; ++ struct r8180_priv *priv = ieee80211_priv(dev); ++ ++ // setup initial timing for RFE ++ // Set VCO-PDN pin. ++ write_nic_word(dev, RFPinsOutput, 0x0480); ++ write_nic_word(dev, RFPinsSelect, 0x2488); ++ write_nic_word(dev, RFPinsEnable, 0x1FFF); ++ ++ mdelay(100); ++ // Steven recommends: delay 1 sec for setting RF 1.8V. by Annie, 2005-04-28. ++ mdelay(1000); ++ ++ // ++ // TODO: Read Zebra version code if necessary. ++ // ++ priv->rf_chip = RF_ZEBRA2; ++} ++ ++ ++void ZEBRA_Config_87BASIC_HardCode(struct net_device* dev) ++{ ++ u32 i; ++ u32 addr,data; ++ u32 u4bRegOffset, u4bRegValue; ++ ++ ++ //============================================================================= ++ // RADIOCFG.TXT ++ //============================================================================= ++ write_rtl8225(dev, 0x00, 0x00b7); mdelay(1); ++ write_rtl8225(dev, 0x01, 0x0ee0); mdelay(1); ++ write_rtl8225(dev, 0x02, 0x044d); mdelay(1); ++ write_rtl8225(dev, 0x03, 0x0441); mdelay(1); ++ write_rtl8225(dev, 0x04, 0x08c3); mdelay(1); ++ write_rtl8225(dev, 0x05, 0x0c72); mdelay(1); ++ write_rtl8225(dev, 0x06, 0x00e6); mdelay(1); ++ write_rtl8225(dev, 0x07, 0x082a); mdelay(1); ++ write_rtl8225(dev, 0x08, 0x003f); mdelay(1); ++ write_rtl8225(dev, 0x09, 0x0335); mdelay(1); ++ write_rtl8225(dev, 0x0a, 0x09d4); mdelay(1); ++ write_rtl8225(dev, 0x0b, 0x07bb); mdelay(1); ++ write_rtl8225(dev, 0x0c, 0x0850); mdelay(1); ++ write_rtl8225(dev, 0x0d, 0x0cdf); mdelay(1); ++ write_rtl8225(dev, 0x0e, 0x002b); mdelay(1); ++ write_rtl8225(dev, 0x0f, 0x0114); mdelay(1); ++ ++ write_rtl8225(dev, 0x00, 0x01b7); mdelay(1); ++ ++ ++ for(i=1;i<=95;i++) ++ { ++ write_rtl8225(dev, 0x01, i);mdelay(1); ++ write_rtl8225(dev, 0x02, ZEBRA_RF_RX_GAIN_TABLE[i]); mdelay(1); ++ //DbgPrint("RF - 0x%x = 0x%x\n", i, ZEBRA_RF_RX_GAIN_TABLE[i]); ++ } ++ ++ write_rtl8225(dev, 0x03, 0x0080); mdelay(1); // write reg 18 ++ write_rtl8225(dev, 0x05, 0x0004); mdelay(1); // write reg 20 ++ write_rtl8225(dev, 0x00, 0x00b7); mdelay(1); // switch to reg0-reg15 ++ //lzm mod for up take too long time 20081201 ++#ifdef THOMAS_BEACON ++ msleep(1000);// Deay 1 sec. //0xfd ++ //msleep(1000);// Deay 1 sec. //0xfd ++ //msleep(1000);// Deay 1 sec. //0xfd ++ msleep(400);// Deay 1 sec. //0xfd ++#else ++ ++ mdelay(1000); ++ //mdelay(1000); ++ //mdelay(1000); ++ mdelay(400); ++#endif ++ write_rtl8225(dev, 0x02, 0x0c4d); mdelay(1); ++ //lzm mod for up take too long time 20081201 ++ //mdelay(1000); ++ //mdelay(1000); ++ msleep(100);// Deay 100 ms. //0xfe ++ msleep(100);// Deay 100 ms. //0xfe ++ write_rtl8225(dev, 0x02, 0x044d); mdelay(1); ++ write_rtl8225(dev, 0x00, 0x02bf); mdelay(1); //0x002f disable 6us corner change, 06f--> enable ++ ++ //============================================================================= ++ ++ //============================================================================= ++ // CCKCONF.TXT ++ //============================================================================= ++ /* ++ u4bRegOffset=0x41; ++ u4bRegValue=0xc8; ++ ++ //DbgPrint("\nCCK- 0x%x = 0x%x\n", u4bRegOffset, u4bRegValue); ++ WriteBB(dev, (0x01000080 | (u4bRegOffset & 0x7f) | ((u4bRegValue & 0xff) << 8))); ++ */ ++ ++ ++ //============================================================================= ++ ++ //============================================================================= ++ // Follow WMAC RTL8225_Config() ++ //============================================================================= ++// // ++// // enable EEM0 and EEM1 in 9346CR ++// PlatformEFIOWrite1Byte(dev, CR9346, PlatformEFIORead1Byte(dev, CR9346)|0xc0); ++// // enable PARM_En in Config3 ++// PlatformEFIOWrite1Byte(dev, CONFIG3, PlatformEFIORead1Byte(dev, CONFIG3)|0x40); ++// ++// PlatformEFIOWrite4Byte(dev, AnaParm2, ANAPARM2_ASIC_ON); //0x727f3f52 ++// PlatformEFIOWrite4Byte(dev, AnaParm, ANAPARM_ASIC_ON); //0x45090658 ++ ++ // power control ++ write_nic_byte(dev, CCK_TXAGC, 0x03); ++ write_nic_byte(dev, OFDM_TXAGC, 0x07); ++ write_nic_byte(dev, ANTSEL, 0x03); ++ ++// // disable PARM_En in Config3 ++// PlatformEFIOWrite1Byte(dev, CONFIG3, PlatformEFIORead1Byte(dev, CONFIG3)&0xbf); ++// // disable EEM0 and EEM1 in 9346CR ++// PlatformEFIOWrite1Byte(dev, CR9346, PlatformEFIORead1Byte(dev, CR9346)&0x3f); ++ //============================================================================= ++ ++ //============================================================================= ++ // AGC.txt ++ //============================================================================= ++ //write_nic_dword( dev, PhyAddr, 0x00001280); // Annie, 2006-05-05 ++ //write_phy_ofdm( dev, 0x00, 0x12); // David, 2006-08-01 ++ write_phy_ofdm( dev, 0x80, 0x12); // David, 2006-08-09 ++ ++ for (i=0; i<128; i++) ++ { ++ //DbgPrint("AGC - [%x+1] = 0x%x\n", i, ZEBRA_AGC[i+1]); ++ ++ data = ZEBRA_AGC[i+1]; ++ data = data << 8; ++ data = data | 0x0000008F; ++ ++ addr = i + 0x80; //enable writing AGC table ++ addr = addr << 8; ++ addr = addr | 0x0000008E; ++ ++ write_phy_ofdm(dev,data&0x7f,(data>>8)&0xff); ++ write_phy_ofdm(dev,addr&0x7f,(addr>>8)&0xff); ++ write_phy_ofdm(dev,0x0E,0x00); ++ } ++ ++ //write_nic_dword(dev, PhyAddr, 0x00001080); // Annie, 2006-05-05 ++ //write_phy_ofdm( dev, 0x00, 0x10); // David, 2006-08-01 ++ write_phy_ofdm( dev, 0x80, 0x10); // David, 2006-08-09 ++ ++ //============================================================================= ++ ++ //============================================================================= ++ // OFDMCONF.TXT ++ //============================================================================= ++ ++ for(i=0; i<60; i++) ++ { ++ u4bRegOffset=i; ++ u4bRegValue=OFDM_CONFIG[i]; ++ //u4bRegValue=OFDM_CONFIG3m82[i]; ++ ++ // write_nic_dword(dev,PhyAddr,(0x00000080 | (u4bRegOffset & 0x7f) | ((u4bRegValue & 0xff) << 8))); ++ write_phy_ofdm(dev,i,u4bRegValue); ++ } ++ ++ ++ //============================================================================= ++} ++ ++void ZEBRA_Config_87BASIC(struct net_device *dev) ++{ ++ ZEBRA_Config_87BASIC_HardCode(dev); ++} ++//by amy for DIG ++// ++// Description: ++// Update initial gain into PHY. ++// ++void ++UpdateCCKThreshold( ++ struct net_device *dev ++ ) ++{ ++ struct r8180_priv *priv = ieee80211_priv(dev); ++ // Update CCK Power Detection(0x41) value. ++ switch(priv->StageCCKTh) ++ { ++ case 0: ++// printk("Update CCK Stage 0: 88 \n"); ++ write_phy_cck(dev, 0xc1, 0x88);mdelay(1); ++ break; ++ ++ case 1: ++// printk("Update CCK Stage 1: 98 \n"); ++ write_phy_cck(dev, 0xc1, 0x98);mdelay(1); ++ break; ++ ++ case 2: ++// printk("Update CCK Stage 2: C8 \n"); ++ write_phy_cck(dev, 0xc1, 0xC8);mdelay(1); ++ break; ++ ++ case 3: ++// printk("Update CCK Stage 3: D8 \n"); ++ write_phy_cck(dev, 0xc1, 0xD8);mdelay(1); ++ break; ++ ++ default: ++// printk("Update CCK Stage %d ERROR!\n", pHalData->StageCCKTh); ++ break; ++ } ++} ++// ++// Description: ++// Update initial gain into PHY. ++// ++void ++UpdateInitialGain( ++ struct net_device *dev ++ ) ++{ ++ struct r8180_priv *priv = ieee80211_priv(dev); ++ //u8 u1Tmp=0; ++ ++ //printk("UpdateInitialGain(): InitialGain: %d RFChipID: %d\n", priv->InitialGain, priv->rf_chip); ++ ++ switch(priv->rf_chip) ++ { ++ case RF_ZEBRA: ++ case RF_ZEBRA2: ++ ++ // ++ // Note: ++ // Whenever we update this gain table, we should be careful about those who call it. ++ // Functions which call UpdateInitialGain as follows are important: ++ // (1)StaRateAdaptive87B ++ // (2)DIG_Zebra ++ // (3)ActSetWirelessMode8187 (when the wireless mode is "B" mode, we set the ++ // OFDM[0x17] = 0x26 to improve the Rx sensitivity). ++ // By Bruce, 2007-06-01. ++ // ++ ++ // ++ // SD3 C.M. Lin Initial Gain Table, by Bruce, 2007-06-01. ++ // ++ switch(priv->InitialGain) ++ { ++ case 1: //m861dBm ++// DMESG("RTL8187 + 8225 Initial Gain State 1: -82 dBm "); ++ write_phy_ofdm(dev, 0x97, 0x26); mdelay(1); ++ write_phy_ofdm(dev, 0xa4, 0x86); mdelay(1); ++ write_phy_ofdm(dev, 0x85, 0xfa); mdelay(1); ++ break; ++ ++ case 2: //m862dBm ++// DMESG("RTL8187 + 8225 Initial Gain State 2: -78 dBm "); ++ write_phy_ofdm(dev, 0x97, 0x36); mdelay(1);// Revise 0x26 to 0x36, by Roger, 2007.05.03. ++ write_phy_ofdm(dev, 0xa4, 0x86); mdelay(1); ++ write_phy_ofdm(dev, 0x85, 0xfa); mdelay(1); ++ break; ++ ++ case 3: //m863dBm ++// DMESG("RTL8187 + 8225 Initial Gain State 3: -78 dBm "); ++ write_phy_ofdm(dev, 0x97, 0x36); mdelay(1);// Revise 0x26 to 0x36, by Roger, 2007.05.03. ++ write_phy_ofdm(dev, 0xa4, 0x86); mdelay(1); ++ write_phy_ofdm(dev, 0x85, 0xfb); mdelay(1); ++ break; ++ ++ case 4: //m864dBm ++// DMESG("RTL8187 + 8225 Initial Gain State 4: -74 dBm "); ++ write_phy_ofdm(dev, 0x97, 0x46); mdelay(1);// Revise 0x26 to 0x36, by Roger, 2007.05.03. ++ write_phy_ofdm(dev, 0xa4, 0x86); mdelay(1); ++ write_phy_ofdm(dev, 0x85, 0xfb); mdelay(1); ++ break; ++ ++ case 5: //m82dBm ++// DMESG("RTL8187 + 8225 Initial Gain State 5: -74 dBm "); ++ write_phy_ofdm(dev, 0x97, 0x46); mdelay(1); ++ write_phy_ofdm(dev, 0xa4, 0x96); mdelay(1); ++ write_phy_ofdm(dev, 0x85, 0xfb); mdelay(1); ++ break; ++ ++ case 6: //m78dBm ++// DMESG("RTL8187 + 8225 Initial Gain State 6: -70 dBm "); ++ write_phy_ofdm(dev, 0x97, 0x56); mdelay(1); ++ write_phy_ofdm(dev, 0xa4, 0x96); mdelay(1); ++ write_phy_ofdm(dev, 0x85, 0xfc); mdelay(1); ++ break; ++ ++ case 7: //m74dBm ++// DMESG("RTL8187 + 8225 Initial Gain State 7: -70 dBm "); ++ write_phy_ofdm(dev, 0x97, 0x56); mdelay(1); ++ write_phy_ofdm(dev, 0xa4, 0xa6); mdelay(1); ++ write_phy_ofdm(dev, 0x85, 0xfc); mdelay(1); ++ break; ++ ++ // By Bruce, 2007-03-29. ++ case 8: ++ write_phy_ofdm(dev, 0x97, 0x66); mdelay(1); ++ write_phy_ofdm(dev, 0xa4, 0xb6); mdelay(1); ++ write_phy_ofdm(dev, 0x85, 0xfc); mdelay(1); ++ break; ++ ++ default: //MP ++// DMESG("RTL8187 + 8225 Initial Gain State: -82 dBm (default), InitialGain(%d)", priv->InitialGain); ++ write_phy_ofdm(dev, 0x97, 0x26); mdelay(1); ++ write_phy_ofdm(dev, 0xa4, 0x86); mdelay(1); ++ write_phy_ofdm(dev, 0x85, 0xfa); mdelay(1); ++ break; ++ } ++ break; ++ ++ default: ++ break; ++ } ++} ++//by amy for DIG ++void PhyConfig8187(struct net_device *dev) ++{ ++ struct r8180_priv *priv = ieee80211_priv(dev); ++ u8 btConfig4; ++ ++ btConfig4 = read_nic_byte(dev, CONFIG4); ++ priv->RFProgType = (btConfig4 & 0x03); ++ ++ ++ ++ switch(priv->rf_chip) ++ { ++ case RF_ZEBRA2: ++ ZEBRA_Config_87BASIC(dev); ++ break; ++ } ++ if(priv->bDigMechanism) ++ { ++ if(priv->InitialGain == 0) ++ priv->InitialGain = 4; ++ //DMESG("DIG is enabled, set default initial gain index to %d", priv->InitialGain); ++ } ++ ++ // By Bruce, 2007-03-29. ++ UpdateCCKThreshold(dev); ++ // Update initial gain after PhyConfig comleted, asked for by SD3 CMLin. ++ UpdateInitialGain(dev); ++ return ; ++} ++ ++u8 GetSupportedWirelessMode8187(struct net_device* dev) ++{ ++ u8 btSupportedWirelessMode; ++ struct r8180_priv *priv = ieee80211_priv(dev); ++ ++ btSupportedWirelessMode = 0; ++ ++ switch(priv->rf_chip) ++ { ++ case RF_ZEBRA: ++ case RF_ZEBRA2: ++ btSupportedWirelessMode = (WIRELESS_MODE_B | WIRELESS_MODE_G); ++ break; ++ default: ++ btSupportedWirelessMode = WIRELESS_MODE_B; ++ break; ++ } ++ return btSupportedWirelessMode; ++} ++ ++void ActUpdateChannelAccessSetting(struct net_device *dev, ++ int WirelessMode, ++ PCHANNEL_ACCESS_SETTING ChnlAccessSetting) ++{ ++ AC_CODING eACI; ++ AC_PARAM AcParam; ++#ifdef TODO ++ PSTA_QOS pStaQos = Adapter->MgntInfo.pStaQos; ++#endif ++ //bool bFollowLegacySetting = false; ++ ++ ++ switch( WirelessMode ) ++ { ++ case WIRELESS_MODE_A: ++ ChnlAccessSetting->SIFS_Timer = 0x22; ++ ChnlAccessSetting->DIFS_Timer = 34; // 34 = 16 + 2*9. 2006.06.07, by rcnjko. ++ ChnlAccessSetting->SlotTimeTimer = 9; ++ ChnlAccessSetting->EIFS_Timer = 23; ++ ChnlAccessSetting->CWminIndex = 4; ++ ChnlAccessSetting->CWmaxIndex = 10; ++ break; ++ ++ case WIRELESS_MODE_B: ++ ChnlAccessSetting->SIFS_Timer = 0x22; ++ ChnlAccessSetting->DIFS_Timer = 50; // 50 = 10 + 2*20. 2006.06.07, by rcnjko. ++ ChnlAccessSetting->SlotTimeTimer = 20; ++ ChnlAccessSetting->EIFS_Timer = 91; ++ ChnlAccessSetting->CWminIndex = 5; ++ ChnlAccessSetting->CWmaxIndex = 10; ++ break; ++ ++ case WIRELESS_MODE_G: ++ // ++ // <RJ_TODO_8185B> ++ // TODO: We still don't know how to set up these registers, just follow WMAC to ++ // verify 8185B FPAG. ++ // ++ // <RJ_TODO_8185B> ++ // Jong said CWmin/CWmax register are not functional in 8185B, ++ // so we shall fill channel access realted register into AC parameter registers, ++ // even in nQBss. ++ // ++ ChnlAccessSetting->SIFS_Timer = 0x22; // Suggested by Jong, 2005.12.08. ++ ChnlAccessSetting->SlotTimeTimer = 9; // 2006.06.07, by rcnjko. ++ ChnlAccessSetting->DIFS_Timer = 28; // 28 = 10 + 2*9. 2006.06.07, by rcnjko. ++ ChnlAccessSetting->EIFS_Timer = 0x5B; // Suggested by wcchu, it is the default value of EIFS register, 2005.12.08. ++#ifdef TODO ++ switch (Adapter->NdisUsbDev.CWinMaxMin) ++#else ++ switch (2) ++#endif ++ { ++ case 0:// 0: [max:7 min:1 ] ++ ChnlAccessSetting->CWminIndex = 1; ++ ChnlAccessSetting->CWmaxIndex = 7; ++ break; ++ case 1:// 1: [max:7 min:2 ] ++ ChnlAccessSetting->CWminIndex = 2; ++ ChnlAccessSetting->CWmaxIndex = 7; ++ break; ++ case 2:// 2: [max:7 min:3 ] ++ ChnlAccessSetting->CWminIndex = 3; ++ ChnlAccessSetting->CWmaxIndex = 7; ++ break; ++ case 3:// 3: [max:9 min:1 ] ++ ChnlAccessSetting->CWminIndex = 1; ++ ChnlAccessSetting->CWmaxIndex = 9; ++ break; ++ case 4:// 4: [max:9 min:2 ] ++ ChnlAccessSetting->CWminIndex = 2; ++ ChnlAccessSetting->CWmaxIndex = 9; ++ break; ++ case 5:// 5: [max:9 min:3 ] ++ ChnlAccessSetting->CWminIndex = 3; ++ ChnlAccessSetting->CWmaxIndex = 9; ++ break; ++ case 6:// 6: [max:A min:5 ] ++ ChnlAccessSetting->CWminIndex = 5; ++ ChnlAccessSetting->CWmaxIndex = 10; ++ break; ++ case 7:// 7: [max:A min:4 ] ++ ChnlAccessSetting->CWminIndex = 4; ++ ChnlAccessSetting->CWmaxIndex = 10; ++ break; ++ ++ default: ++ ChnlAccessSetting->CWminIndex = 1; ++ ChnlAccessSetting->CWmaxIndex = 7; ++ break; ++ } ++#ifdef TODO ++ if( Adapter->MgntInfo.OpMode == RT_OP_MODE_IBSS) ++ { ++ ChnlAccessSetting->CWminIndex= 4; ++ ChnlAccessSetting->CWmaxIndex= 10; ++ } ++#endif ++ break; ++ } ++ ++ ++ write_nic_byte(dev, SIFS, ChnlAccessSetting->SIFS_Timer); ++//{ update slot time related by david, 2006-7-21 ++ write_nic_byte(dev, SLOT, ChnlAccessSetting->SlotTimeTimer); // Rewrited from directly use PlatformEFIOWrite1Byte(), by Annie, 2006-03-29. ++#ifdef TODO ++ if(pStaQos->CurrentQosMode > QOS_DISABLE) ++ { ++ for(eACI = 0; eACI < AC_MAX; eACI++) ++ { ++ Adapter->HalFunc.SetHwRegHandler(Adapter, HW_VAR_AC_PARAM, \ ++ (pu1Byte)(&(pStaQos->WMMParamEle.AcParam[eACI])) ); ++ } ++ } ++ else ++#endif ++ { ++ u8 u1bAIFS = aSifsTime + (2 * ChnlAccessSetting->SlotTimeTimer ); ++ ++ write_nic_byte(dev, AC_VO_PARAM, u1bAIFS); ++ write_nic_byte(dev, AC_VI_PARAM, u1bAIFS); ++ write_nic_byte(dev, AC_BE_PARAM, u1bAIFS); ++ write_nic_byte(dev, AC_BK_PARAM, u1bAIFS); ++ } ++//} ++ ++ write_nic_byte(dev, EIFS_8187B, ChnlAccessSetting->EIFS_Timer); ++ write_nic_byte(dev, AckTimeOutReg, 0x5B); // <RJ_EXPR_QOS> Suggested by wcchu, it is the default value of EIFS register, 2005.12.08. ++#ifdef TODO ++ // <RJ_TODO_NOW_8185B> Update ECWmin/ECWmax, AIFS, TXOP Limit of each AC to the value defined by SPEC. ++ if( pStaQos->CurrentQosMode > QOS_DISABLE ) ++ { // QoS mode. ++ if(pStaQos->QBssWirelessMode == WirelessMode) ++ { ++ // Follow AC Parameters of the QBSS. ++ for(eACI = 0; eACI < AC_MAX; eACI++) ++ { ++ Adapter->HalFunc.SetHwRegHandler(Adapter, HW_VAR_AC_PARAM, (pu1Byte)(&(pStaQos->WMMParamEle.AcParam[eACI])) ); ++ } ++ } ++ else ++ { ++ // Follow Default WMM AC Parameters. ++ bFollowLegacySetting = TRUE; ++ } ++ } ++ else ++ { // Legacy 802.11. ++ bFollowLegacySetting = TRUE; ++ } ++ ++ if(bFollowLegacySetting) ++#endif ++ if(true) ++ { ++ // ++ // Follow 802.11 seeting to AC parameter, all AC shall use the same parameter. ++ // 2005.12.01, by rcnjko. ++ // ++ AcParam.longData = 0; ++ AcParam.f.AciAifsn.f.AIFSN = 2; // Follow 802.11 DIFS. ++ AcParam.f.AciAifsn.f.ACM = 0; ++ AcParam.f.Ecw.f.ECWmin = ChnlAccessSetting->CWminIndex; // Follow 802.11 CWmin. ++ AcParam.f.Ecw.f.ECWmax = ChnlAccessSetting->CWmaxIndex; // Follow 802.11 CWmax. ++ AcParam.f.TXOPLimit = 0; ++ for(eACI = 0; eACI < AC_MAX; eACI++) ++ { ++ AcParam.f.AciAifsn.f.ACI = (u8)eACI; ++ { ++ PAC_PARAM pAcParam = (PAC_PARAM)(&AcParam); ++ AC_CODING eACI; ++ u8 u1bAIFS; ++ u32 u4bAcParam; ++ ++ // Retrive paramters to udpate. ++ eACI = pAcParam->f.AciAifsn.f.ACI; ++ u1bAIFS = pAcParam->f.AciAifsn.f.AIFSN * ChnlAccessSetting->SlotTimeTimer + aSifsTime; ++ u4bAcParam = ( (((u32)(pAcParam->f.TXOPLimit)) << AC_PARAM_TXOP_LIMIT_OFFSET) | ++ (((u32)(pAcParam->f.Ecw.f.ECWmax)) << AC_PARAM_ECW_MAX_OFFSET) | ++ (((u32)(pAcParam->f.Ecw.f.ECWmin)) << AC_PARAM_ECW_MIN_OFFSET) | ++ (((u32)u1bAIFS) << AC_PARAM_AIFS_OFFSET)); ++ ++ switch(eACI) ++ { ++ case AC1_BK: ++ write_nic_dword(dev, AC_BK_PARAM, u4bAcParam); ++ break; ++ ++ case AC0_BE: ++ write_nic_dword(dev, AC_BE_PARAM, u4bAcParam); ++ break; ++ ++ case AC2_VI: ++ write_nic_dword(dev, AC_VI_PARAM, u4bAcParam); ++ break; ++ ++ case AC3_VO: ++ write_nic_dword(dev, AC_VO_PARAM, u4bAcParam); ++ break; ++ ++ default: ++ printk(KERN_WARNING "SetHwReg8185(): invalid ACI: %d !\n", eACI); ++ break; ++ } ++ ++ // Cehck ACM bit. ++ // If it is set, immediately set ACM control bit to downgrading AC for passing WMM testplan. Annie, 2005-12-13. ++ //write_nic_byte(dev, ACM_CONTROL, pAcParam->f.AciAifsn); ++ { ++ PACI_AIFSN pAciAifsn = (PACI_AIFSN)(&pAcParam->f.AciAifsn); ++ AC_CODING eACI = pAciAifsn->f.ACI; ++ ++ //modified Joseph ++ //for 8187B AsynIORead issue ++#ifdef TODO ++ u8 AcmCtrl = pHalData->AcmControl; ++#else ++ u8 AcmCtrl = 0; ++#endif ++ if( pAciAifsn->f.ACM ) ++ { // ACM bit is 1. ++ switch(eACI) ++ { ++ case AC0_BE: ++ AcmCtrl |= (BEQ_ACM_EN|BEQ_ACM_CTL|ACM_HW_EN); // or 0x21 ++ break; ++ ++ case AC2_VI: ++ AcmCtrl |= (VIQ_ACM_EN|VIQ_ACM_CTL|ACM_HW_EN); // or 0x42 ++ break; ++ ++ case AC3_VO: ++ AcmCtrl |= (VOQ_ACM_EN|VOQ_ACM_CTL|ACM_HW_EN); // or 0x84 ++ break; ++ ++ default: ++ printk(KERN_WARNING "SetHwReg8185(): [HW_VAR_ACM_CTRL] ACM set\ ++ failed: eACI is %d\n", eACI ); ++ break; ++ } ++ } ++ else ++ { // ACM bit is 0. ++ switch(eACI) ++ { ++ case AC0_BE: ++ AcmCtrl &= ( (~BEQ_ACM_EN) & (~BEQ_ACM_CTL) & (~ACM_HW_EN) ); // and 0xDE ++ break; ++ ++ case AC2_VI: ++ AcmCtrl &= ( (~VIQ_ACM_EN) & (~VIQ_ACM_CTL) & (~ACM_HW_EN) ); // and 0xBD ++ break; ++ ++ case AC3_VO: ++ AcmCtrl &= ( (~VOQ_ACM_EN) & (~VOQ_ACM_CTL) & (~ACM_HW_EN) ); // and 0x7B ++ break; ++ ++ default: ++ break; ++ } ++ } ++ ++ //printk(KERN_WARNING "SetHwReg8185(): [HW_VAR_ACM_CTRL] Write 0x%X\n", AcmCtrl); ++ ++#ifdef TO_DO ++ pHalData->AcmControl = AcmCtrl; ++#endif ++ write_nic_byte(dev, ACM_CONTROL, AcmCtrl); ++ } ++ } ++ } ++ } ++} ++ ++void ActSetWirelessMode8187(struct net_device* dev, u8 btWirelessMode) ++{ ++ struct r8180_priv *priv = ieee80211_priv(dev); ++ struct ieee80211_device *ieee = priv->ieee80211; ++ //PMGNT_INFO pMgntInfo = &(pAdapter->MgntInfo); ++ u8 btSupportedWirelessMode = GetSupportedWirelessMode8187(dev); ++ ++ if( (btWirelessMode & btSupportedWirelessMode) == 0 ) ++ { // Don't switch to unsupported wireless mode, 2006.02.15, by rcnjko. ++ printk(KERN_WARNING "ActSetWirelessMode8187(): WirelessMode(%d) is not supported (%d)!\n", ++ btWirelessMode, btSupportedWirelessMode); ++ return; ++ } ++ ++ // 1. Assign wireless mode to swtich if necessary. ++ if( (btWirelessMode == WIRELESS_MODE_AUTO) || ++ (btWirelessMode & btSupportedWirelessMode) == 0 ) ++ { ++ if((btSupportedWirelessMode & WIRELESS_MODE_A)) ++ { ++ btWirelessMode = WIRELESS_MODE_A; ++ } ++ else if((btSupportedWirelessMode & WIRELESS_MODE_G)) ++ { ++ btWirelessMode = WIRELESS_MODE_G; ++ } ++ else if((btSupportedWirelessMode & WIRELESS_MODE_B)) ++ { ++ btWirelessMode = WIRELESS_MODE_B; ++ } ++ else ++ { ++ printk(KERN_WARNING "MptActSetWirelessMode8187(): No valid wireless mode supported, \ ++ btSupportedWirelessMode(%x)!!!\n", btSupportedWirelessMode); ++ btWirelessMode = WIRELESS_MODE_B; ++ } ++ } ++ ++ // 2. Swtich band. ++ switch(priv->rf_chip) ++ { ++ case RF_ZEBRA: ++ case RF_ZEBRA2: ++ { ++ // Update current wireless mode if we swtich to specified band successfully. ++ ieee->mode = (WIRELESS_MODE)btWirelessMode; ++ } ++ break; ++ ++ default: ++ printk(KERN_WARNING "MptActSetWirelessMode8187(): unsupported RF: 0x%X !!!\n", priv->rf_chip); ++ break; ++ } ++ ++ // 4. Change related setting. ++#if 0 ++ if( ieee->mode == WIRELESS_MODE_A ){ ++ DMESG("WIRELESS_MODE_A"); ++ } ++ else if(ieee->mode == WIRELESS_MODE_B ){ ++ DMESG("WIRELESS_MODE_B"); ++ } ++ else if( ieee->mode == WIRELESS_MODE_G ){ ++ DMESG("WIRELESS_MODE_G"); ++ } ++#endif ++ ActUpdateChannelAccessSetting(dev, ieee->mode, &priv->ChannelAccessSetting ); ++//by amy 0305 ++#ifdef TODO ++ if(ieee->mode == WIRELESS_MODE_B && priv->InitialGain > pHalData->RegBModeGainStage) ++ { ++ pHalData->InitialGain = pHalData->RegBModeGainStage; // B mode, OFDM[0x17] = 26. ++ RT_TRACE(COMP_INIT | COMP_DIG, DBG_LOUD, ("ActSetWirelessMode8187(): update init_gain to index %d for B mode\n",pHalData->InitialGain)); ++ PlatformScheduleWorkItem( &(pHalData->UpdateDigWorkItem) ); ++ } ++// pAdapter->MgntInfo.dot11CurrentWirelessMode = pHalData->CurrentWirelessMode; ++// MgntSetRegdot11OperationalRateSet( pAdapter ); ++#endif ++//by amy 0305 ++} ++ ++ ++void ++InitializeExtraRegsOn8185(struct net_device *dev) ++{ ++ struct r8180_priv *priv = ieee80211_priv(dev); ++ struct ieee80211_device *ieee = priv->ieee80211; ++ //RTL8185_TODO: Determine Retrylimit, TxAGC, AutoRateFallback control. ++ bool bUNIVERSAL_CONTROL_RL = false; // Enable per-packet tx retry, 2005.03.31, by rcnjko. ++ bool bUNIVERSAL_CONTROL_AGC = true;//false; ++ bool bUNIVERSAL_CONTROL_ANT = true;//false; ++ bool bAUTO_RATE_FALLBACK_CTL = true; ++ u8 val8; ++ ++ // Set up ACK rate. ++ // Suggested by wcchu, 2005.08.25, by rcnjko. ++ // 1. Initialize (MinRR, MaxRR) to (6,24) for A/G. ++ // 2. MUST Set RR before BRSR. ++ // 3. CCK must be basic rate. ++ if((ieee->mode == IEEE_G)||(ieee->mode == IEEE_A)) ++ { ++ write_nic_word(dev, BRSR_8187B, 0x0fff); ++ } ++ else ++ { ++ write_nic_word(dev, BRSR_8187B, 0x000f); ++ } ++ ++ ++ // Retry limit ++ val8 = read_nic_byte(dev, CW_CONF); ++ if(bUNIVERSAL_CONTROL_RL) ++ { ++ val8 &= (~CW_CONF_PERPACKET_RETRY_LIMIT); ++ } ++ else ++ { ++ val8 |= CW_CONF_PERPACKET_RETRY_LIMIT; ++ } ++ ++ write_nic_byte(dev, CW_CONF, val8); ++ ++ // Tx AGC ++ val8 = read_nic_byte(dev, TX_AGC_CTL); ++ if(bUNIVERSAL_CONTROL_AGC) ++ { ++ val8 &= (~TX_AGC_CTL_PER_PACKET_TXAGC); ++ write_nic_byte(dev, CCK_TXAGC, 128); ++ write_nic_byte(dev, OFDM_TXAGC, 128); ++ } ++ else ++ { ++ val8 |= TX_AGC_CTL_PER_PACKET_TXAGC; ++ } ++ write_nic_byte(dev, TX_AGC_CTL, val8); ++ ++ // Tx Antenna including Feedback control ++ val8 = read_nic_byte(dev, TX_AGC_CTL); ++ ++ if(bUNIVERSAL_CONTROL_ANT) ++ { ++ write_nic_byte(dev, ANTSEL, 0x00); ++ val8 &= (~TXAGC_CTL_PER_PACKET_ANT_SEL); ++ } ++ else ++ { ++ val8 |= TXAGC_CTL_PER_PACKET_ANT_SEL; ++ } ++ write_nic_byte(dev, TX_AGC_CTL, val8); ++ ++ // Auto Rate fallback control ++ val8 = read_nic_byte(dev, RATE_FALLBACK); ++ if( bAUTO_RATE_FALLBACK_CTL ) ++ { ++ val8 |= RATE_FALLBACK_CTL_ENABLE | RATE_FALLBACK_CTL_AUTO_STEP0; ++ ++ // <RJ_TODO_8187B> We shall set up the ARFR according to user's setting. ++ write_nic_word(dev, ARFR, 0x0fff); // set 1M ~ 54M ++ } ++ else ++ { ++ val8 &= (~RATE_FALLBACK_CTL_ENABLE); ++ } ++ write_nic_byte(dev, RATE_FALLBACK, val8); ++ ++} ++/////////////////////////// ++void rtl8225z2_rf_init(struct net_device *dev) ++{ ++ ++ struct r8180_priv *priv = ieee80211_priv(dev); ++ if (NIC_8187B == priv->card_8187){ ++ struct ieee80211_device *ieee = priv->ieee80211; ++ u8 InitWirelessMode; ++ u8 SupportedWirelessMode; ++ bool bInvalidWirelessMode = false; ++ InitializeExtraRegsOn8185(dev); ++ ++ write_nic_byte(dev, MSR, read_nic_byte(dev,MSR) & 0xf3); // default network type to 'No Link' ++ //{to avoid tx stall ++ write_nic_byte(dev, MSR, read_nic_byte(dev, MSR)|MSR_LINK_ENEDCA);//should always set ENDCA bit ++ write_nic_byte(dev, ACM_CONTROL, priv->AcmControl); ++ ++ write_nic_word(dev, BcnIntv, 100); ++ write_nic_word(dev, AtimWnd, 2); ++ write_nic_word(dev, FEMR, 0xFFFF); ++ //LED TYPE ++ { ++ write_nic_byte(dev, CONFIG1,((read_nic_byte(dev, CONFIG1)&0x3f)|0x80)); //turn on bit 5:Clkrun_mode ++ } ++ write_nic_byte(dev, CR9346, 0x0); // disable config register write ++ ++ //{ add some info here ++ write_nic_dword(dev, MAC0, ((u32*)dev->dev_addr)[0]); ++ write_nic_word(dev, MAC4, ((u32*)dev->dev_addr)[1] & 0xffff ); ++ ++ write_nic_byte(dev, WPA_CONFIG, 0); ++ //} ++ ++ MacConfig_87BASIC(dev); ++ ++ // Override the RFSW_CTRL (MAC offset 0x272-0x273), 2006.06.07, by rcnjko. ++ write_nic_word(dev, RFSW_CTRL, 0x569a); ++#ifdef JOHN_TKIP ++ { ++ void CamResetAllEntry(struct net_device *dev); ++ void EnableHWSecurityConfig8187(struct net_device *dev); ++ CamResetAllEntry(dev); ++ EnableHWSecurityConfig8187(dev); ++ write_nic_word(dev, AESMSK_FC, AESMSK_FC_DEFAULT); mdelay(1); ++ write_nic_word(dev, AESMSK_SC, AESMSK_SC_DEFAULT); mdelay(1); ++ write_nic_word(dev, AESMSK_QC, AESMSK_QC_DEFAULT); mdelay(1); ++ } ++#endif ++ //----------------------------------------------------------------------------- ++ // Set up PHY related. ++ //----------------------------------------------------------------------------- ++ // Enable Config3.PARAM_En to revise AnaaParm. ++ write_nic_byte(dev, CR9346, 0xC0); ++ write_nic_byte(dev, CONFIG3, read_nic_byte(dev,CONFIG3)|CONFIG3_PARM_En); ++ write_nic_byte(dev, CR9346, 0x0); ++ ++ // Initialize RFE and read Zebra2 version code. Added by Annie, 2005-08-01. ++ SetupRFEInitialTiming(dev); ++ // PHY config. ++ PhyConfig8187(dev); ++ ++ // We assume RegWirelessMode has already been initialized before, ++ // however, we has to validate the wireless mode here and provide a reasonble ++ // initialized value if necessary. 2005.01.13, by rcnjko. ++ SupportedWirelessMode = GetSupportedWirelessMode8187(dev); ++ ++ if((ieee->mode != WIRELESS_MODE_B) && ++ (ieee->mode != WIRELESS_MODE_G) && ++ (ieee->mode != WIRELESS_MODE_A) && ++ (ieee->mode != WIRELESS_MODE_AUTO)) ++ { // It should be one of B, G, A, or AUTO. ++ bInvalidWirelessMode = true; ++ } ++ else ++ { // One of B, G, A, or AUTO. ++ // Check if the wireless mode is supported by RF. ++ if( (ieee->mode != WIRELESS_MODE_AUTO) && ++ (ieee->mode & SupportedWirelessMode) == 0 ) ++ { ++ bInvalidWirelessMode = true; ++ } ++ } ++ ++ if(bInvalidWirelessMode || ieee->mode==WIRELESS_MODE_AUTO) ++ { // Auto or other invalid value. ++ // Assigne a wireless mode to initialize. ++ if((SupportedWirelessMode & WIRELESS_MODE_A)) ++ { ++ InitWirelessMode = WIRELESS_MODE_A; ++ } ++ else if((SupportedWirelessMode & WIRELESS_MODE_G)) ++ { ++ ++ InitWirelessMode = WIRELESS_MODE_G; ++ } ++ else if((SupportedWirelessMode & WIRELESS_MODE_B)) ++ { ++ ++ InitWirelessMode = WIRELESS_MODE_B; ++ } ++ else ++ { ++ printk(KERN_WARNING ++ "InitializeAdapter8187(): No valid wireless mode supported, SupportedWirelessMode(%x)!!!\n", ++ SupportedWirelessMode); ++ InitWirelessMode = WIRELESS_MODE_B; ++ } ++ ++ // Initialize RegWirelessMode if it is not a valid one. ++ if(bInvalidWirelessMode) ++ { ++ ieee->mode = (WIRELESS_MODE)InitWirelessMode; ++ } ++ } ++ else ++ { // One of B, G, A. ++ InitWirelessMode = ieee->mode; ++ } ++ ActSetWirelessMode8187(dev, (u8)(InitWirelessMode)); ++ {//added for init gain ++ write_phy_ofdm(dev, 0x97, 0x46); mdelay(1); ++ write_phy_ofdm(dev, 0xa4, 0xb6); mdelay(1); ++ write_phy_ofdm(dev, 0x85, 0xfc); mdelay(1); ++ write_phy_cck(dev, 0xc1, 0x88); mdelay(1); ++ } ++ ++ } ++ else{ ++ int i; ++ short channel = 1; ++ u16 brsr; ++ u32 data,addr; ++ ++ priv->chan = channel; ++ ++ rtl8180_set_anaparam(dev, RTL8225_ANAPARAM_ON); ++ ++ if(priv->card_type == USB) ++ rtl8225_host_usb_init(dev); ++ else ++ rtl8225_host_pci_init(dev); ++ ++ write_nic_dword(dev, RF_TIMING, 0x000a8008); ++ ++ brsr = read_nic_word(dev, BRSR_8187); ++ ++ write_nic_word(dev, BRSR_8187, 0xffff); ++ ++ ++ write_nic_dword(dev, RF_PARA, 0x100044); ++ ++ #if 1 //0->1 ++ rtl8180_set_mode(dev, EPROM_CMD_CONFIG); ++ write_nic_byte(dev, CONFIG3, 0x44); ++ rtl8180_set_mode(dev, EPROM_CMD_NORMAL); ++ #endif ++ ++ ++ rtl8185_rf_pins_enable(dev); ++ ++ // mdelay(1000); ++ ++ write_rtl8225(dev, 0x0, 0x2bf); mdelay(1); ++ ++ ++ write_rtl8225(dev, 0x1, 0xee0); mdelay(1); ++ ++ write_rtl8225(dev, 0x2, 0x44d); mdelay(1); ++ ++ write_rtl8225(dev, 0x3, 0x441); mdelay(1); ++ ++ ++ write_rtl8225(dev, 0x4, 0x8c3);mdelay(1); ++ ++ ++ ++ write_rtl8225(dev, 0x5, 0xc72);mdelay(1); ++ // } ++ ++ write_rtl8225(dev, 0x6, 0xe6); mdelay(1); ++ ++ write_rtl8225(dev, 0x7, ((priv->card_type == USB)? 0x82a : rtl8225_chan[channel])); mdelay(1); ++ ++ write_rtl8225(dev, 0x8, 0x3f); mdelay(1); ++ ++ write_rtl8225(dev, 0x9, 0x335); mdelay(1); ++ ++ write_rtl8225(dev, 0xa, 0x9d4); mdelay(1); ++ ++ write_rtl8225(dev, 0xb, 0x7bb); mdelay(1); ++ ++ write_rtl8225(dev, 0xc, 0x850); mdelay(1); ++ ++ ++ write_rtl8225(dev, 0xd, 0xcdf); mdelay(1); ++ ++ write_rtl8225(dev, 0xe, 0x2b); mdelay(1); ++ ++ write_rtl8225(dev, 0xf, 0x114); ++ ++ ++ mdelay(100); ++ ++ ++ //if(priv->card_type != USB) /* maybe not needed even for 8185 */ ++ // write_rtl8225(dev, 0x7, rtl8225_chan[channel]); ++ ++ write_rtl8225(dev, 0x0, 0x1b7); ++ ++ for(i=0;i<95;i++){ ++ write_rtl8225(dev, 0x1, (u8)(i+1)); ++ /* version B & C & D*/ ++ write_rtl8225(dev, 0x2, rtl8225z2_rxgain[i]); ++ } ++ //write_rtl8225(dev, 0x3, 0x80); ++ write_rtl8225(dev, 0x3, 0x2); ++ write_rtl8225(dev, 0x5, 0x4); ++ ++ write_rtl8225(dev, 0x0, 0xb7); ++ ++ write_rtl8225(dev, 0x2, 0xc4d); ++ ++ if(priv->card_type == USB){ ++ // force_pci_posting(dev); ++ mdelay(200); ++ ++ write_rtl8225(dev, 0x2, 0x44d); ++ ++ // force_pci_posting(dev); ++ mdelay(200); ++ ++ }//End of if(priv->card_type == USB) ++ /* FIXME!! rtl8187 we have to check if calibrarion ++ * is successful and eventually cal. again (repeat ++ * the two write on reg 2) ++ */ ++ // Check for calibration status, 2005.11.17, ++ data = read_rtl8225(dev, 6); ++ if (!(data&0x00000080)) ++ { ++ write_rtl8225(dev, 0x02, 0x0c4d); ++ force_pci_posting(dev); mdelay(200); ++ write_rtl8225(dev, 0x02, 0x044d); ++ force_pci_posting(dev); mdelay(100); ++ data = read_rtl8225(dev, 6); ++ if (!(data&0x00000080)) ++ { ++ DMESGW("RF Calibration Failed!!!!\n"); ++ } ++ } ++ //force_pci_posting(dev); ++ ++ mdelay(200); //200 for 8187 ++ ++ ++ // //if(priv->card_type != USB){ ++ // write_rtl8225(dev, 0x2, 0x44d); ++ // write_rtl8225(dev, 0x7, rtl8225_chan[channel]); ++ // write_rtl8225(dev, 0x2, 0x47d); ++ // ++ // force_pci_posting(dev); ++ // mdelay(100); ++ // ++ // write_rtl8225(dev, 0x2, 0x44d); ++ // //} ++ ++ write_rtl8225(dev, 0x0, 0x2bf); ++ ++ if(priv->card_type != USB) ++ rtl8185_rf_pins_enable(dev); ++ //set up ZEBRA AGC table, 2005.11.17, ++ for(i=0;i<128;i++){ ++ data = rtl8225_agc[i]; ++ ++ addr = i + 0x80; //enable writing AGC table ++ write_phy_ofdm(dev, 0xb, data); ++ ++ mdelay(1); ++ write_phy_ofdm(dev, 0xa, addr); ++ ++ mdelay(1); ++ } ++ ++ force_pci_posting(dev); ++ mdelay(1); ++ ++ write_phy_ofdm(dev, 0x0, 0x1); mdelay(1); ++ write_phy_ofdm(dev, 0x1, 0x2); mdelay(1); ++ write_phy_ofdm(dev, 0x2, ((priv->card_type == USB)? 0x42 : 0x62)); mdelay(1); ++ write_phy_ofdm(dev, 0x3, 0x0); mdelay(1); ++ write_phy_ofdm(dev, 0x4, 0x0); mdelay(1); ++ write_phy_ofdm(dev, 0x5, 0x0); mdelay(1); ++ write_phy_ofdm(dev, 0x6, 0x40); mdelay(1); ++ write_phy_ofdm(dev, 0x7, 0x0); mdelay(1); ++ write_phy_ofdm(dev, 0x8, 0x40); mdelay(1); ++ write_phy_ofdm(dev, 0x9, 0xfe); mdelay(1); ++ ++ write_phy_ofdm(dev, 0xa, 0x8); mdelay(1); ++ ++ //write_phy_ofdm(dev, 0x18, 0xef); ++ // } ++ //} ++ write_phy_ofdm(dev, 0xb, 0x80); mdelay(1); ++ ++ write_phy_ofdm(dev, 0xc, 0x1);mdelay(1); ++ ++ ++ //if(priv->card_type != USB) ++ write_phy_ofdm(dev, 0xd, 0x43); ++ ++ write_phy_ofdm(dev, 0xe, 0xd3);mdelay(1); ++ ++ write_phy_ofdm(dev, 0xf, 0x38);mdelay(1); ++ /*ver D & 8187*/ ++ // } ++ ++ // if(priv->card_8185 == 1 && priv->card_8185_Bversion) ++ // write_phy_ofdm(dev, 0x10, 0x04);/*ver B*/ ++ // else ++ write_phy_ofdm(dev, 0x10, 0x84);mdelay(1); ++ /*ver C & D & 8187*/ ++ ++ write_phy_ofdm(dev, 0x11, 0x07);mdelay(1); ++ /*agc resp time 700*/ ++ ++ ++ // if(priv->card_8185 == 2){ ++ /* Ver D & 8187*/ ++ write_phy_ofdm(dev, 0x12, 0x20);mdelay(1); ++ ++ write_phy_ofdm(dev, 0x13, 0x20);mdelay(1); ++ ++ write_phy_ofdm(dev, 0x14, 0x0); mdelay(1); ++ write_phy_ofdm(dev, 0x15, 0x40); mdelay(1); ++ write_phy_ofdm(dev, 0x16, 0x0); mdelay(1); ++ write_phy_ofdm(dev, 0x17, 0x40); mdelay(1); ++ ++ // if (priv->card_type == USB) ++ // write_phy_ofdm(dev, 0x18, 0xef); ++ ++ write_phy_ofdm(dev, 0x18, 0xef);mdelay(1); ++ ++ ++ write_phy_ofdm(dev, 0x19, 0x19); mdelay(1); ++ write_phy_ofdm(dev, 0x1a, 0x20); mdelay(1); ++ write_phy_ofdm(dev, 0x1b, 0x15);mdelay(1); ++ ++ write_phy_ofdm(dev, 0x1c, 0x4);mdelay(1); ++ ++ write_phy_ofdm(dev, 0x1d, 0xc5);mdelay(1); //2005.11.17, ++ ++ write_phy_ofdm(dev, 0x1e, 0x95);mdelay(1); ++ ++ write_phy_ofdm(dev, 0x1f, 0x75); mdelay(1); ++ ++ // } ++ ++ write_phy_ofdm(dev, 0x20, 0x1f);mdelay(1); ++ ++ write_phy_ofdm(dev, 0x21, 0x17);mdelay(1); ++ ++ write_phy_ofdm(dev, 0x22, 0x16);mdelay(1); ++ ++ // if(priv->card_type != USB) ++ write_phy_ofdm(dev, 0x23, 0x80);mdelay(1); //FIXME maybe not needed // <> ++ ++ write_phy_ofdm(dev, 0x24, 0x46); mdelay(1); ++ write_phy_ofdm(dev, 0x25, 0x00); mdelay(1); ++ write_phy_ofdm(dev, 0x26, 0x90); mdelay(1); ++ ++ write_phy_ofdm(dev, 0x27, 0x88); mdelay(1); ++ ++ ++ // <> Set init. gain to m74dBm. ++ ++ rtl8225z2_set_gain(dev,4); ++ //rtl8225z2_set_gain(dev,2); ++ ++ write_phy_cck(dev, 0x0, 0x98); mdelay(1); ++ write_phy_cck(dev, 0x3, 0x20); mdelay(1); ++ write_phy_cck(dev, 0x4, 0x7e); mdelay(1); ++ write_phy_cck(dev, 0x5, 0x12); mdelay(1); ++ write_phy_cck(dev, 0x6, 0xfc); mdelay(1); ++ write_phy_cck(dev, 0x7, 0x78);mdelay(1); ++ /* Ver C & D & 8187*/ ++ write_phy_cck(dev, 0x8, 0x2e);mdelay(1); ++ ++ write_phy_cck(dev, 0x9, 0x11);mdelay(1); ++ write_phy_cck(dev, 0xa, 0x17);mdelay(1); ++ write_phy_cck(dev, 0xb, 0x11);mdelay(1); ++ ++ write_phy_cck(dev, 0x10, ((priv->card_type == USB) ? 0x9b: 0x93)); mdelay(1); ++ write_phy_cck(dev, 0x11, 0x88); mdelay(1); ++ write_phy_cck(dev, 0x12, 0x47); mdelay(1); ++ write_phy_cck(dev, 0x13, 0xd0); /* Ver C & D & 8187*/ ++ ++ write_phy_cck(dev, 0x19, 0x0); mdelay(1); ++ write_phy_cck(dev, 0x1a, 0xa0); mdelay(1); ++ write_phy_cck(dev, 0x1b, 0x8); mdelay(1); ++ write_phy_cck(dev, 0x1d, 0x0); mdelay(1); ++ ++ write_phy_cck(dev, 0x40, 0x86); /* CCK Carrier Sense Threshold */ mdelay(1); ++ ++ write_phy_cck(dev, 0x41, 0x9d);mdelay(1); ++ ++ ++ write_phy_cck(dev, 0x42, 0x15); mdelay(1); ++ write_phy_cck(dev, 0x43, 0x18); mdelay(1); ++ ++ ++ write_phy_cck(dev, 0x44, 0x36); mdelay(1); ++ write_phy_cck(dev, 0x45, 0x35); mdelay(1); ++ write_phy_cck(dev, 0x46, 0x2e); mdelay(1); ++ write_phy_cck(dev, 0x47, 0x25); mdelay(1); ++ write_phy_cck(dev, 0x48, 0x1c); mdelay(1); ++ write_phy_cck(dev, 0x49, 0x12); mdelay(1); ++ write_phy_cck(dev, 0x4a, 0x09); mdelay(1); ++ write_phy_cck(dev, 0x4b, 0x04); mdelay(1); ++ write_phy_cck(dev, 0x4c, 0x5);mdelay(1); ++ ++ ++ write_nic_byte(dev, 0x5b, 0x0d); mdelay(1); ++ ++ ++ ++ // <> ++ // // TESTR 0xb 8187 ++ // write_phy_cck(dev, 0x10, 0x93);// & 0xfb); ++ // ++ // //if(priv->card_type != USB){ ++ // write_phy_ofdm(dev, 0x2, 0x62); ++ // write_phy_ofdm(dev, 0x6, 0x0); ++ // write_phy_ofdm(dev, 0x8, 0x0); ++ // //} ++ ++ rtl8225z2_SetTXPowerLevel(dev, channel); ++ ++ write_phy_cck(dev, 0x10, 0x9b); mdelay(1); /* Rx ant A, 0xdb for B */ ++ write_phy_ofdm(dev, 0x26, 0x90); mdelay(1); /* Rx ant A, 0x10 for B */ ++ ++ rtl8185_tx_antenna(dev, 0x3); /* TX ant A, 0x0 for B */ ++ ++ /* switch to high-speed 3-wire ++ * last digit. 2 for both cck and ofdm ++ */ ++ if(priv->card_type == USB) ++ write_nic_dword(dev, 0x94, 0x3dc00002); ++ else{ ++ write_nic_dword(dev, 0x94, 0x15c00002); ++ rtl8185_rf_pins_enable(dev); ++ } ++ ++ // if(priv->card_type != USB) ++ // rtl8225_set_gain(dev, 4); /* FIXME this '1' is random */ // <> ++ // rtl8225_set_mode(dev, 1); /* FIXME start in B mode */ // <> ++ // ++ // /* make sure is waken up! */ ++ // write_rtl8225(dev,0x4, 0x9ff); ++ // rtl8180_set_anaparam(dev, RTL8225_ANAPARAM_ON); ++ // rtl8185_set_anaparam2(dev, RTL8225_ANAPARAM2_ON); ++ ++ rtl8225_rf_set_chan(dev, priv->chan); ++ ++ //write_nic_word(dev,BRSR,brsr); ++ ++ //rtl8225z2_rf_set_mode(dev); ++ } ++} ++ ++void rtl8225z2_rf_set_mode(struct net_device *dev) ++{ ++ struct r8180_priv *priv = ieee80211_priv(dev); ++ ++ if(priv->ieee80211->mode == IEEE_A) ++ { ++ write_rtl8225(dev, 0x5, 0x1865); ++ write_nic_dword(dev, RF_PARA, 0x10084); ++ write_nic_dword(dev, RF_TIMING, 0xa8008); ++ write_phy_ofdm(dev, 0x0, 0x0); ++ write_phy_ofdm(dev, 0xa, 0x6); ++ write_phy_ofdm(dev, 0xb, 0x99); ++ write_phy_ofdm(dev, 0xf, 0x20); ++ write_phy_ofdm(dev, 0x11, 0x7); ++ ++ rtl8225z2_set_gain(dev,4); ++ ++ write_phy_ofdm(dev,0x15, 0x40); ++ write_phy_ofdm(dev,0x17, 0x40); ++ ++ write_nic_dword(dev, 0x94,0x10000000); ++ }else{ ++ ++ write_rtl8225(dev, 0x5, 0x1864); ++ write_nic_dword(dev, RF_PARA, 0x10044); ++ write_nic_dword(dev, RF_TIMING, 0xa8008); ++ write_phy_ofdm(dev, 0x0, 0x1); ++ write_phy_ofdm(dev, 0xa, 0x6); ++ write_phy_ofdm(dev, 0xb, 0x99); ++ write_phy_ofdm(dev, 0xf, 0x20); ++ write_phy_ofdm(dev, 0x11, 0x7); ++ ++ rtl8225z2_set_gain(dev,4); ++ ++ write_phy_ofdm(dev,0x15, 0x40); ++ write_phy_ofdm(dev,0x17, 0x40); ++ ++ write_nic_dword(dev, 0x94,0x04000002); ++ } ++} +diff -Nur linux-2.6.33/drivers/net/wireless/rtl8187b/r8180_wx.c linux-lemote/drivers/net/wireless/rtl8187b/r8180_wx.c +--- linux-2.6.33/drivers/net/wireless/rtl8187b/r8180_wx.c 1970-01-01 01:00:00.000000000 +0100 ++++ linux-lemote/drivers/net/wireless/rtl8187b/r8180_wx.c 2010-03-06 16:43:22.000000000 +0100 +@@ -0,0 +1,2067 @@ ++/* ++ This file contains wireless extension handlers. ++ ++ This is part of rtl8180 OpenSource driver. ++ Copyright (C) Andrea Merello 2004-2005 <andreamrl@tiscali.it> ++ Released under the terms of GPL (General Public Licence) ++ ++ Parts of this driver are based on the GPL part ++ of the official realtek driver. ++ ++ Parts of this driver are based on the rtl8180 driver skeleton ++ from Patric Schenke & Andres Salomon. ++ ++ Parts of this driver are based on the Intel Pro Wireless 2100 GPL driver. ++ ++ We want to tanks the Authors of those projects and the Ndiswrapper ++ project Authors. ++*/ ++ ++ ++ ++#include "r8187.h" ++#include "r8180_hw.h" ++//added 1117 ++#include "ieee80211/ieee80211.h" ++#ifdef ENABLE_DOT11D ++#include "dot11d.h" ++#endif ++ ++ ++//#define RATE_COUNT 4 ++u32 rtl8180_rates[] = {1000000,2000000,5500000,11000000, ++ 6000000,9000000,12000000,18000000,24000000,36000000,48000000,54000000}; ++#define RATE_COUNT sizeof(rtl8180_rates)/(sizeof(rtl8180_rates[0])) ++ ++#ifdef _RTL8187_EXT_PATCH_ ++#define IW_MODE_MESH 11 ++static int r8180_wx_join_mesh(struct net_device *dev, struct iw_request_info *info, union iwreq_data *wrqu, char *extra); ++int r8180_wx_set_channel(struct net_device *dev, struct iw_request_info *info, union iwreq_data *wrqu, char *extra); ++static int r8180_wx_mesh_scan(struct net_device *dev, struct iw_request_info *info, union iwreq_data *wrqu, char *extra); ++static int r8180_wx_get_mesh_list(struct net_device *dev, struct iw_request_info *info, union iwreq_data *wrqu, char *extra); ++#endif ++ ++static int r8180_wx_get_freq(struct net_device *dev, ++ struct iw_request_info *a, ++ union iwreq_data *wrqu, char *b) ++{ ++ struct r8180_priv *priv = ieee80211_priv(dev); ++ ++ return ieee80211_wx_get_freq(priv->ieee80211,a,wrqu,b); ++} ++ ++ ++#if 0 ++ ++static int r8180_wx_set_beaconinterval(struct net_device *dev, struct iw_request_info *aa, ++ union iwreq_data *wrqu, char *b) ++{ ++ int *parms = (int *)b; ++ int bi = parms[0]; ++ ++ struct r8180_priv *priv = ieee80211_priv(dev); ++ if(priv->ieee80211->bHwRadioOff) ++ return 0; ++ down(&priv->wx_sem); ++ DMESG("setting beacon interval to %x",bi); ++ ++ priv->ieee80211->beacon_interval=bi; ++ rtl8180_commit(dev); ++ up(&priv->wx_sem); ++ ++ return 0; ++} ++ ++ ++static int r8180_wx_set_forceassociate(struct net_device *dev, struct iw_request_info *aa, ++ union iwreq_data *wrqu, char *extra) ++{ ++ struct r8180_priv *priv=ieee80211_priv(dev); ++ int *parms = (int *)extra; ++ if(priv->ieee80211->bHwRadioOff) ++ return 0; ++ ++ priv->ieee80211->force_associate = (parms[0] > 0); ++ ++ ++ return 0; ++} ++ ++#endif ++static int r8180_wx_get_mode(struct net_device *dev, struct iw_request_info *a, ++ union iwreq_data *wrqu, char *b) ++{ ++ struct r8180_priv *priv=ieee80211_priv(dev); ++ ++ return ieee80211_wx_get_mode(priv->ieee80211,a,wrqu,b); ++} ++ ++ ++ ++static int r8180_wx_get_rate(struct net_device *dev, ++ struct iw_request_info *info, ++ union iwreq_data *wrqu, char *extra) ++{ ++ struct r8180_priv *priv = ieee80211_priv(dev); ++ return ieee80211_wx_get_rate(priv->ieee80211,info,wrqu,extra); ++} ++ ++ ++ ++static int r8180_wx_set_rate(struct net_device *dev, ++ struct iw_request_info *info, ++ union iwreq_data *wrqu, char *extra) ++{ ++ int ret; ++ struct r8180_priv *priv = ieee80211_priv(dev); ++ if(priv->ieee80211->bHwRadioOff) ++ return 0; ++ ++ down(&priv->wx_sem); ++ ++ ret = ieee80211_wx_set_rate(priv->ieee80211,info,wrqu,extra); ++ ++ up(&priv->wx_sem); ++ ++ return ret; ++} ++#ifdef JOHN_IOCTL ++u16 read_rtl8225(struct net_device *dev, u8 addr); ++void write_rtl8225(struct net_device *dev, u8 adr, u16 data); ++u32 john_read_rtl8225(struct net_device *dev, u8 adr); ++void _write_rtl8225(struct net_device *dev, u8 adr, u16 data); ++ ++static int r8180_wx_read_regs(struct net_device *dev, ++ struct iw_request_info *info, ++ union iwreq_data *wrqu, char *extra) ++{ ++ struct r8180_priv *priv = ieee80211_priv(dev); ++ u8 addr = 0; ++ u16 data1; ++ ++ down(&priv->wx_sem); ++ ++ ++ get_user(addr,(u8*)wrqu->data.pointer); ++ data1 = read_rtl8225(dev, addr); ++ wrqu->data.length = data1; ++ ++ up(&priv->wx_sem); ++ return 0; ++ ++} ++ ++static int r8180_wx_write_regs(struct net_device *dev, ++ struct iw_request_info *info, ++ union iwreq_data *wrqu, char *extra) ++{ ++ struct r8180_priv *priv = ieee80211_priv(dev); ++ u8 addr = 0; ++ ++ down(&priv->wx_sem); ++ ++ get_user(addr, (u8*)wrqu->data.pointer); ++ write_rtl8225(dev, addr, wrqu->data.length); ++ ++ up(&priv->wx_sem); ++ return 0; ++ ++} ++ ++void rtl8187_write_phy(struct net_device *dev, u8 adr, u32 data); ++u8 rtl8187_read_phy(struct net_device *dev,u8 adr, u32 data); ++ ++static int r8180_wx_read_bb(struct net_device *dev, ++ struct iw_request_info *info, ++ union iwreq_data *wrqu, char *extra) ++{ ++ struct r8180_priv *priv = ieee80211_priv(dev); ++ u8 databb; ++#if 0 ++ int i; ++ for(i=0;i<12;i++) printk("%8x\n", read_cam(dev, i) ); ++#endif ++ ++ down(&priv->wx_sem); ++ ++ databb = rtl8187_read_phy(dev, (u8)wrqu->data.length, 0x00000000); ++ wrqu->data.length = databb; ++ ++ up(&priv->wx_sem); ++ return 0; ++} ++ ++void rtl8187_write_phy(struct net_device *dev, u8 adr, u32 data); ++static int r8180_wx_write_bb(struct net_device *dev, ++ struct iw_request_info *info, ++ union iwreq_data *wrqu, char *extra) ++{ ++ struct r8180_priv *priv = ieee80211_priv(dev); ++ u8 databb = 0; ++ ++ down(&priv->wx_sem); ++ ++ get_user(databb, (u8*)wrqu->data.pointer); ++ rtl8187_write_phy(dev, wrqu->data.length, databb); ++ ++ up(&priv->wx_sem); ++ return 0; ++ ++} ++ ++ ++static int r8180_wx_write_nicb(struct net_device *dev, ++ struct iw_request_info *info, ++ union iwreq_data *wrqu, char *extra) ++{ ++ struct r8180_priv *priv = ieee80211_priv(dev); ++ u32 addr = 0; ++ ++ down(&priv->wx_sem); ++ ++ get_user(addr, (u32*)wrqu->data.pointer); ++ write_nic_byte(dev, addr, wrqu->data.length); ++ ++ up(&priv->wx_sem); ++ return 0; ++ ++} ++static int r8180_wx_read_nicb(struct net_device *dev, ++ struct iw_request_info *info, ++ union iwreq_data *wrqu, char *extra) ++{ ++ struct r8180_priv *priv = ieee80211_priv(dev); ++ u32 addr = 0; ++ u16 data1; ++ ++ down(&priv->wx_sem); ++ ++ get_user(addr,(u32*)wrqu->data.pointer); ++ data1 = read_nic_byte(dev, addr); ++ wrqu->data.length = data1; ++ ++ up(&priv->wx_sem); ++ return 0; ++} ++ ++static inline int is_same_network(struct ieee80211_network *src, ++ struct ieee80211_network *dst, ++ struct ieee80211_device *ieee) ++{ ++ /* A network is only a duplicate if the channel, BSSID, ESSID ++ * and the capability field (in particular IBSS and BSS) all match. ++ * We treat all <hidden> with the same BSSID and channel ++ * as one network */ ++ return (((src->ssid_len == dst->ssid_len)||(ieee->iw_mode == IW_MODE_INFRA)) && //YJ,mod, 080819,for hidden ap ++ //((src->ssid_len == dst->ssid_len) && ++ (src->channel == dst->channel) && ++ !memcmp(src->bssid, dst->bssid, ETH_ALEN) && ++ (!memcmp(src->ssid, dst->ssid, src->ssid_len)||(ieee->iw_mode == IW_MODE_INFRA)) && //YJ,mod, 080819,for hidden ap ++ //!memcmp(src->ssid, dst->ssid, src->ssid_len) && ++ ((src->capability & WLAN_CAPABILITY_IBSS) == ++ (dst->capability & WLAN_CAPABILITY_IBSS)) && ++ ((src->capability & WLAN_CAPABILITY_BSS) == ++ (dst->capability & WLAN_CAPABILITY_BSS))); ++} ++ ++static int r8180_wx_get_ap_status(struct net_device *dev, ++ struct iw_request_info *info, ++ union iwreq_data *wrqu, char *extra) ++{ ++ struct r8180_priv *priv = ieee80211_priv(dev); ++ struct ieee80211_device *ieee = priv->ieee80211; ++ struct ieee80211_network *target; ++ int name_len; ++ ++ down(&priv->wx_sem); ++ ++ //count the length of input ssid ++ for(name_len=0 ; ((char*)wrqu->data.pointer)[name_len]!='\0' ; name_len++); ++ ++ //search for the correspoding info which is received ++ list_for_each_entry(target, &ieee->network_list, list) { ++ if ( (target->ssid_len == name_len) && ++ (strncmp(target->ssid, (char*)wrqu->data.pointer, name_len)==0)){ ++ if( ((jiffies-target->last_scanned)/HZ > 1) && (ieee->state == IEEE80211_LINKED) && (is_same_network(&ieee->current_network,target, ieee)) ) ++ wrqu->data.length = 999; ++ else ++ wrqu->data.length = target->SignalStrength; ++ if(target->wpa_ie_len>0 || target->rsn_ie_len>0 ) ++ //set flags=1 to indicate this ap is WPA ++ wrqu->data.flags = 1; ++ else wrqu->data.flags = 0; ++ ++ ++ break; ++ } ++ } ++ ++ if (&target->list == &ieee->network_list){ ++ wrqu->data.flags = 3; ++ } ++ up(&priv->wx_sem); ++ return 0; ++} ++ ++ ++ ++#endif ++ ++static int r8180_wx_set_rawtx(struct net_device *dev, ++ struct iw_request_info *info, ++ union iwreq_data *wrqu, char *extra) ++{ ++ struct r8180_priv *priv = ieee80211_priv(dev); ++ int ret; ++ ++ if(priv->ieee80211->bHwRadioOff) ++ return 0; ++ ++ down(&priv->wx_sem); ++ ++ ret = ieee80211_wx_set_rawtx(priv->ieee80211, info, wrqu, extra); ++ ++ up(&priv->wx_sem); ++ ++ return ret; ++ ++} ++ ++static int r8180_wx_set_crcmon(struct net_device *dev, ++ struct iw_request_info *info, ++ union iwreq_data *wrqu, char *extra) ++{ ++ struct r8180_priv *priv = ieee80211_priv(dev); ++ int *parms = (int *)extra; ++ int enable = (parms[0] > 0); ++ short prev = priv->crcmon; ++ ++ if(priv->ieee80211->bHwRadioOff) ++ return 0; ++ ++ down(&priv->wx_sem); ++ ++ if(enable) ++ priv->crcmon=1; ++ else ++ priv->crcmon=0; ++ ++ DMESG("bad CRC in monitor mode are %s", ++ priv->crcmon ? "accepted" : "rejected"); ++ ++ if(prev != priv->crcmon && priv->up){ ++ rtl8180_down(dev); ++ rtl8180_up(dev); ++ } ++ ++ up(&priv->wx_sem); ++ ++ return 0; ++} ++ ++static int r8180_wx_set_mode(struct net_device *dev, struct iw_request_info *a, ++ union iwreq_data *wrqu, char *b) ++{ ++ struct r8180_priv *priv = ieee80211_priv(dev); ++ int ret; ++ if(priv->ieee80211->bHwRadioOff) ++ return 0; ++ ++#ifdef _RTL8187_EXT_PATCH_ ++ if (priv->mshobj && (priv->ieee80211->iw_ext_mode==11)) return 0; ++#endif ++ down(&priv->wx_sem); ++ ++#ifdef CONFIG_IPS ++ if(priv->bInactivePs){ ++ if(wrqu->mode != IW_MODE_INFRA){ ++ down(&priv->ieee80211->ips_sem); ++ IPSLeave(dev); ++ up(&priv->ieee80211->ips_sem); ++ } ++ } ++#endif ++ ret = ieee80211_wx_set_mode(priv->ieee80211,a,wrqu,b); ++ ++ rtl8187_set_rxconf(dev); ++ ++ up(&priv->wx_sem); ++ return ret; ++} ++ ++ ++//YJ,add,080819,for hidden ap ++struct iw_range_with_scan_capa ++{ ++ /* Informative stuff (to choose between different interface) */ ++ __u32 throughput; /* To give an idea... */ ++ /* In theory this value should be the maximum benchmarked ++ * TCP/IP throughput, because with most of these devices the ++ * bit rate is meaningless (overhead an co) to estimate how ++ * fast the connection will go and pick the fastest one. ++ * I suggest people to play with Netperf or any benchmark... ++ */ ++ ++ /* NWID (or domain id) */ ++ __u32 min_nwid; /* Minimal NWID we are able to set */ ++ __u32 max_nwid; /* Maximal NWID we are able to set */ ++ ++ /* Old Frequency (backward compat - moved lower ) */ ++ __u16 old_num_channels; ++ __u8 old_num_frequency; ++ ++ /* Scan capabilities */ ++ __u8 scan_capa; ++}; ++//YJ,add,080819,for hidden ap ++ ++static int rtl8180_wx_get_range(struct net_device *dev, ++ struct iw_request_info *info, ++ union iwreq_data *wrqu, char *extra) ++{ ++ struct iw_range *range = (struct iw_range *)extra; ++ struct r8180_priv *priv = ieee80211_priv(dev); ++ u16 val; ++ int i; ++ struct iw_range_with_scan_capa* tmp = (struct iw_range_with_scan_capa*)range; //YJ,add,080819,for hidden ap ++ ++ wrqu->data.length = sizeof(*range); ++ memset(range, 0, sizeof(*range)); ++ ++ /* Let's try to keep this struct in the same order as in ++ * linux/include/wireless.h ++ */ ++ ++ /* TODO: See what values we can set, and remove the ones we can't ++ * set, or fill them with some default data. ++ */ ++ ++ /* ~5 Mb/s real (802.11b) */ ++ range->throughput = 5 * 1000 * 1000; ++ ++ // TODO: Not used in 802.11b? ++// range->min_nwid; /* Minimal NWID we are able to set */ ++ // TODO: Not used in 802.11b? ++// range->max_nwid; /* Maximal NWID we are able to set */ ++ ++ /* Old Frequency (backward compat - moved lower ) */ ++// range->old_num_channels; ++// range->old_num_frequency; ++// range->old_freq[6]; /* Filler to keep "version" at the same offset */ ++ if(priv->rf_set_sens != NULL) ++ range->sensitivity = priv->max_sens; /* signal level threshold range */ ++ ++ range->max_qual.qual = 100; ++ /* TODO: Find real max RSSI and stick here */ ++ range->max_qual.level = 0; ++ range->max_qual.noise = -98; ++ range->max_qual.updated = 7; /* Updated all three */ ++ ++ range->avg_qual.qual = 92; /* > 8% missed beacons is 'bad' */ ++ /* TODO: Find real 'good' to 'bad' threshol value for RSSI */ ++ range->avg_qual.level = 20 + -98; ++ range->avg_qual.noise = 0; ++ range->avg_qual.updated = 7; /* Updated all three */ ++ ++ range->num_bitrates = RATE_COUNT; ++ ++ for (i = 0; i < RATE_COUNT && i < IW_MAX_BITRATES; i++) { ++ range->bitrate[i] = rtl8180_rates[i]; ++ } ++ ++ range->min_frag = MIN_FRAG_THRESHOLD; ++ range->max_frag = MAX_FRAG_THRESHOLD; ++ ++ range->pm_capa = 0; ++ ++ range->we_version_compiled = WIRELESS_EXT; ++ range->we_version_source = 16; ++ ++// range->retry_capa; /* What retry options are supported */ ++// range->retry_flags; /* How to decode max/min retry limit */ ++// range->r_time_flags; /* How to decode max/min retry life */ ++// range->min_retry; /* Minimal number of retries */ ++// range->max_retry; /* Maximal number of retries */ ++// range->min_r_time; /* Minimal retry lifetime */ ++// range->max_r_time; /* Maximal retry lifetime */ ++ ++ range->num_channels = 14; ++ ++ for (i = 0, val = 0; i < 14; i++) { ++ ++ // Include only legal frequencies for some countries ++#ifdef ENABLE_DOT11D ++ if ((GET_DOT11D_INFO(priv->ieee80211)->channel_map)[i+1]) { ++#else ++ if ((priv->ieee80211->channel_map)[i+1]) { ++#endif ++ range->freq[val].i = i + 1; ++ range->freq[val].m = ieee80211_wlan_frequencies[i] * 100000; ++ range->freq[val].e = 1; ++ val++; ++ } else { ++ // FIXME: do we need to set anything for channels ++ // we don't use ? ++ } ++ ++ if (val == IW_MAX_FREQUENCIES) ++ break; ++ } ++ ++ range->num_frequency = val; ++ range->enc_capa = IW_ENC_CAPA_WPA | IW_ENC_CAPA_WPA2 | ++ IW_ENC_CAPA_CIPHER_TKIP | IW_ENC_CAPA_CIPHER_CCMP; ++ ++ tmp->scan_capa = 0x01; //YJ,add,080819,for hidden ap ++ ++ return 0; ++} ++ ++ ++static int r8180_wx_set_scan(struct net_device *dev, struct iw_request_info *a, ++ union iwreq_data *wrqu, char *b) ++{ ++ struct r8180_priv *priv = ieee80211_priv(dev); ++ struct ieee80211_device* ieee = priv->ieee80211; ++ int ret; ++ ++ if(priv->ieee80211->bHwRadioOff) ++ return 0; ++ //printk("==============>%s()\n",__FUNCTION__); ++ if(!priv->up) ++ return -1; ++ ++ if (wrqu->data.flags & IW_SCAN_THIS_ESSID) ++ { ++ struct iw_scan_req* req = (struct iw_scan_req*)b; ++ if (req->essid_len) ++ { ++ ieee->current_network.ssid_len = req->essid_len; ++ memcpy(ieee->current_network.ssid, req->essid, req->essid_len); ++ } ++ } ++ ++ //set Tr switch to hardware control to scan more bss ++ if(priv->TrSwitchState == TR_SW_TX) { ++ //YJ,add,080611 ++ write_nic_byte(dev, RFPinsSelect, (u8)(priv->wMacRegRfPinsSelect)); ++ write_nic_byte(dev, RFPinsOutput, (u8)(priv->wMacRegRfPinsOutput)); ++ //YJ,add,080611,end ++ priv->TrSwitchState = TR_HW_CONTROLLED; ++ } ++#ifdef _RTL8187_EXT_PATCH_ ++ if((priv->ieee80211->iw_mode == IW_MODE_MESH) && (priv->ieee80211->iw_ext_mode == IW_MODE_MESH)){ ++ r8180_wx_mesh_scan(dev,a,wrqu,b); ++ ret = 0; ++ } ++ else ++#endif ++ { ++ down(&priv->wx_sem); ++ if(priv->ieee80211->state != IEEE80211_LINKED){ ++ //printk("===>start no link scan\n"); ++ //ieee80211_start_scan(priv->ieee80211); ++ //lzm mod 090115 because wq can't scan complete once ++ //because after start protocal wq scan is in doing ++ //so we should stop it first. ++ ieee80211_stop_scan(priv->ieee80211); ++ ieee80211_start_scan_syncro(priv->ieee80211); ++ ret = 0; ++ } else { ++ ret = ieee80211_wx_set_scan(priv->ieee80211,a,wrqu,b); ++ } ++ up(&priv->wx_sem); ++ } ++ return ret; ++} ++ ++ ++static int r8180_wx_get_scan(struct net_device *dev, struct iw_request_info *a, ++ union iwreq_data *wrqu, char *b) ++{ ++ ++ int ret; ++ struct r8180_priv *priv = ieee80211_priv(dev); ++ ++ if(!priv->up) return -1; ++#ifdef _RTL8187_EXT_PATCH_ ++ if((priv->ieee80211->iw_mode == IW_MODE_MESH) && (priv->ieee80211->iw_ext_mode == IW_MODE_MESH)){ ++ ret = r8180_wx_get_mesh_list(dev, a, wrqu, b); ++ } ++ else ++#endif ++ { ++ down(&priv->wx_sem); ++ ++ ret = ieee80211_wx_get_scan(priv->ieee80211,a,wrqu,b); ++ ++ up(&priv->wx_sem); ++ } ++ return ret; ++} ++ ++ ++static int r8180_wx_set_essid(struct net_device *dev, ++ struct iw_request_info *a, ++ union iwreq_data *wrqu, char *b) ++{ ++ struct r8180_priv *priv = ieee80211_priv(dev); ++ int ret; ++#ifdef _RTL8187_EXT_PATCH_ ++ struct ieee80211_device *ieee = priv->ieee80211; ++ char ch = 0; ++ char tmpmeshid[32]; ++ char *p; ++ int tmpmeshid_len=0; ++ int i; ++ short proto_started; ++#endif ++ if(priv->ieee80211->bHwRadioOff) ++ return 0; ++ //printk("==========>%s()\n",__FUNCTION__); ++ down(&priv->wx_sem); ++ ++#ifdef _RTL8187_EXT_PATCH_ ++ if((priv->ieee80211->iw_mode == IW_MODE_MESH) && (priv->ieee80211->iw_ext_mode == IW_MODE_MESH)){ ++ if (wrqu->essid.length > IW_ESSID_MAX_SIZE){ ++ ret= -E2BIG; ++ goto out; ++ } ++ if (wrqu->essid.flags && (wrqu->essid.length > 1)) { ++ memset(tmpmeshid,0,32); ++#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,20) ++ tmpmeshid_len=wrqu->essid.length; ++#else ++ tmpmeshid_len=wrqu->essid.length + 1; ++#endif ++ p=b+tmpmeshid_len-2; ++ for(i=tmpmeshid_len-1;i>0;i--) ++ { ++ if((*p)=='@') ++ break; ++ p--; ++ } ++ if((i == 0) || (i == 1)){ ++ printk("error:wrong meshid\n"); ++ ret = -1; ++ goto out; ++ } ++ ++ memcpy(tmpmeshid,b,(i-1)); ++ p++; ++ if((tmpmeshid_len-1-i)==1) ++ { ++ if(*p > '9'|| *p <= '0'){ ++ goto out; ++ } else { ++ ch = *p - '0'; ++ } ++ } ++ else if((tmpmeshid_len-1-i)==2) ++ { ++ if((*p == '1') && (*(p+1) >= '0') && (*(p+1) <= '9')) ++ ch = (*p - '0') * 10 + (*(p+1) - '0'); ++ else ++ goto out; ++ } ++ else { ++ ret = 0; ++ goto out; ++ } ++ if(ch > 14) ++ { ++ ret = 0; ++ printk("channel is invalid: %d\n",ch); ++ goto out; ++ } ++ ieee->sync_scan_hurryup = 1; ++ ++ proto_started = ieee->proto_started; ++ if(proto_started) ++ ieee80211_stop_protocol(ieee); ++ ++ printk("==============>tmpmeshid is %s\n",tmpmeshid); ++ priv->mshobj->ext_patch_r8180_wx_set_meshID(dev, tmpmeshid); ++ priv->mshobj->ext_patch_r8180_wx_set_mesh_chan(dev,ch); ++ r8180_wx_set_channel(dev, NULL, NULL, &ch); ++ if (proto_started) ++ ieee80211_start_protocol(ieee); ++ } ++ else{ ++ printk("BUG:meshid is null\n"); ++ ret=0; ++ goto out; ++ } ++ ++ ret = 0; ++ } ++ else ++#endif ++ { ++ ret = ieee80211_wx_set_essid(priv->ieee80211,a,wrqu,b); ++ } ++ ++#ifdef _RTL8187_EXT_PATCH_ ++out: ++#endif ++ up(&priv->wx_sem); ++ return ret; ++} ++ ++ ++static int r8180_wx_get_essid(struct net_device *dev, ++ struct iw_request_info *a, ++ union iwreq_data *wrqu, char *b) ++{ ++ int ret; ++ struct r8180_priv *priv = ieee80211_priv(dev); ++ ++ down(&priv->wx_sem); ++ ++ ret = ieee80211_wx_get_essid(priv->ieee80211, a, wrqu, b); ++ ++ up(&priv->wx_sem); ++ ++ return ret; ++} ++ ++ ++static int r8180_wx_set_freq(struct net_device *dev, struct iw_request_info *a, ++ union iwreq_data *wrqu, char *b) ++{ ++ int ret; ++ struct r8180_priv *priv = ieee80211_priv(dev); ++ ++ if(priv->ieee80211->bHwRadioOff) ++ return 0; ++ ++ down(&priv->wx_sem); ++ ++ ret = ieee80211_wx_set_freq(priv->ieee80211, a, wrqu, b); ++ ++ up(&priv->wx_sem); ++ return ret; ++} ++ ++static int r8180_wx_get_name(struct net_device *dev, ++ struct iw_request_info *info, ++ union iwreq_data *wrqu, char *extra) ++{ ++ struct r8180_priv *priv = ieee80211_priv(dev); ++ return ieee80211_wx_get_name(priv->ieee80211, info, wrqu, extra); ++} ++ ++ ++static int r8180_wx_set_frag(struct net_device *dev, ++ struct iw_request_info *info, ++ union iwreq_data *wrqu, char *extra) ++{ ++ struct r8180_priv *priv = ieee80211_priv(dev); ++ ++ if(priv->ieee80211->bHwRadioOff) ++ return 0; ++ ++ if (wrqu->frag.disabled) ++ priv->ieee80211->fts = DEFAULT_FRAG_THRESHOLD; ++ else { ++ if (wrqu->frag.value < MIN_FRAG_THRESHOLD || ++ wrqu->frag.value > MAX_FRAG_THRESHOLD) ++ return -EINVAL; ++ ++ priv->ieee80211->fts = wrqu->frag.value & ~0x1; ++ } ++ ++ return 0; ++} ++ ++ ++static int r8180_wx_get_frag(struct net_device *dev, ++ struct iw_request_info *info, ++ union iwreq_data *wrqu, char *extra) ++{ ++ struct r8180_priv *priv = ieee80211_priv(dev); ++ ++ wrqu->frag.value = priv->ieee80211->fts; ++ wrqu->frag.fixed = 0; /* no auto select */ ++ wrqu->frag.disabled = (wrqu->frag.value == DEFAULT_FRAG_THRESHOLD); ++ ++ return 0; ++} ++ ++ ++static int r8180_wx_set_wap(struct net_device *dev, ++ struct iw_request_info *info, ++ union iwreq_data *awrq, ++ char *extra) ++{ ++ int ret; ++ struct r8180_priv *priv = ieee80211_priv(dev); ++ if(priv->ieee80211->bHwRadioOff) ++ return 0; ++ ++ //printk("in function %s\n",__FUNCTION__); ++#ifdef _RTL8187_EXT_PATCH_ ++ if (priv->mshobj && (priv->ieee80211->iw_ext_mode==11)){ ++ return 0; ++ } ++#endif ++ down(&priv->wx_sem); ++ ++ ret = ieee80211_wx_set_wap(priv->ieee80211,info,awrq,extra); ++ ++ up(&priv->wx_sem); ++ return ret; ++ ++} ++ ++ ++static int r8180_wx_get_wap(struct net_device *dev, ++ struct iw_request_info *info, ++ union iwreq_data *wrqu, char *extra) ++{ ++ struct r8180_priv *priv = ieee80211_priv(dev); ++ ++ return ieee80211_wx_get_wap(priv->ieee80211,info,wrqu,extra); ++} ++ ++ ++static int r8180_wx_get_enc(struct net_device *dev, ++ struct iw_request_info *info, ++ union iwreq_data *wrqu, char *key) ++{ ++ struct r8180_priv *priv = ieee80211_priv(dev); ++ ++ return ieee80211_wx_get_encode(priv->ieee80211, info, wrqu, key); ++} ++ ++static int r8180_wx_set_enc(struct net_device *dev, ++ struct iw_request_info *info, ++ union iwreq_data *wrqu, char *key) ++{ ++ struct r8180_priv *priv = ieee80211_priv(dev); ++ int ret; ++#ifdef JOHN_HWSEC ++// struct ieee80211_device *ieee = priv->ieee80211; ++// u32 TargetContent; ++ u32 hwkey[4]={0,0,0,0}; ++ u8 mask=0xff; ++ u32 key_idx=0; ++ u8 broadcast_addr[6] ={ 0xff,0xff,0xff,0xff,0xff,0xff}; ++ u8 zero_addr[4][6] ={ {0x00,0x00,0x00,0x00,0x00,0x00}, ++ {0x00,0x00,0x00,0x00,0x00,0x01}, ++ {0x00,0x00,0x00,0x00,0x00,0x02}, ++ {0x00,0x00,0x00,0x00,0x00,0x03} }; ++ int i; ++ ++#endif ++ ++ if(priv->ieee80211->bHwRadioOff) ++ return 0; ++ ++ down(&priv->wx_sem); ++ ++ DMESG("Setting SW wep key"); ++ ret = ieee80211_wx_set_encode(priv->ieee80211,info,wrqu,key); ++ ++ up(&priv->wx_sem); ++ ++#ifdef JOHN_HWSEC ++ ++ //sometimes, the length is zero while we do not type key value ++ if(wrqu->encoding.length!=0){ ++ ++ for(i=0 ; i<4 ; i++){ ++ hwkey[i] |= key[4*i+0]&mask; ++ if(i==1&&(4*i+1)==wrqu->encoding.length) mask=0x00; ++ if(i==3&&(4*i+1)==wrqu->encoding.length) mask=0x00; ++ hwkey[i] |= (key[4*i+1]&mask)<<8; ++ hwkey[i] |= (key[4*i+2]&mask)<<16; ++ hwkey[i] |= (key[4*i+3]&mask)<<24; ++ } ++ ++ #define CONF_WEP40 0x4 ++ #define CONF_WEP104 0x14 ++ ++ switch(wrqu->encoding.flags){ ++ case 0: ++ case 1: key_idx = 0; break; ++ case 2: key_idx = 1; break; ++ case 3: key_idx = 2; break; ++ case 4: key_idx = 3; break; ++ default: break; ++ } ++ ++ if(wrqu->encoding.length==0x5){ ++ setKey( dev, ++ key_idx, //EntryNo ++ key_idx, //KeyIndex ++ KEY_TYPE_WEP40, //KeyType ++ zero_addr[key_idx], ++ 0, //DefaultKey ++ hwkey); //KeyContent ++ ++ if(key_idx == 0){ ++ ++ write_nic_byte(dev, WPA_CONFIG, 7); ++ ++ setKey( dev, ++ 4, //EntryNo ++ key_idx, //KeyIndex ++ KEY_TYPE_WEP40, //KeyType ++ broadcast_addr, //addr ++ 0, //DefaultKey ++ hwkey); //KeyContent ++ } ++ } ++ ++ else if(wrqu->encoding.length==0xd){ ++ setKey( dev, ++ key_idx, //EntryNo ++ key_idx, //KeyIndex ++ KEY_TYPE_WEP104, //KeyType ++ zero_addr[key_idx], ++ 0, //DefaultKey ++ hwkey); //KeyContent ++ ++ if(key_idx == 0){ ++ ++ write_nic_byte(dev, WPA_CONFIG, 7); ++ ++ setKey( dev, ++ 4, //EntryNo ++ key_idx, //KeyIndex ++ KEY_TYPE_WEP104, //KeyType ++ broadcast_addr, //addr ++ 0, //DefaultKey ++ hwkey); //KeyContent ++ } ++ } ++ else printk("wrong type in WEP, not WEP40 and WEP104\n"); ++ ++ } ++ ++ //consider the setting different key index situation ++ //wrqu->encoding.flags = 801 means that we set key with index "1" ++ if(wrqu->encoding.length==0 && (wrqu->encoding.flags >>8) == 0x8 ){ ++ ++ write_nic_byte(dev, WPA_CONFIG, 7); ++ ++ //copy wpa config from default key(key0~key3) to broadcast key(key5) ++ // ++ key_idx = (wrqu->encoding.flags & 0xf)-1 ; ++ write_cam(dev, (4*6), 0xffff0000|read_cam(dev, key_idx*6) ); ++ write_cam(dev, (4*6)+1, 0xffffffff); ++ write_cam(dev, (4*6)+2, read_cam(dev, (key_idx*6)+2) ); ++ write_cam(dev, (4*6)+3, read_cam(dev, (key_idx*6)+3) ); ++ write_cam(dev, (4*6)+4, read_cam(dev, (key_idx*6)+4) ); ++ write_cam(dev, (4*6)+5, read_cam(dev, (key_idx*6)+5) ); ++ } ++ ++#endif /*JOHN_HWSEC*/ ++ return ret; ++} ++ ++ ++static int r8180_wx_set_scan_type(struct net_device *dev, struct iw_request_info *aa, union ++ iwreq_data *wrqu, char *p){ ++ ++ struct r8180_priv *priv = ieee80211_priv(dev); ++ int *parms=(int*)p; ++ int mode=parms[0]; ++ ++ if(priv->ieee80211->bHwRadioOff) ++ return 0; ++ ++ priv->ieee80211->active_scan = mode; ++ ++ return 1; ++} ++ ++ ++ ++static int r8180_wx_set_retry(struct net_device *dev, ++ struct iw_request_info *info, ++ union iwreq_data *wrqu, char *extra) ++{ ++ struct r8180_priv *priv = ieee80211_priv(dev); ++ int err = 0; ++ ++ if(priv->ieee80211->bHwRadioOff) ++ return 0; ++ ++ down(&priv->wx_sem); ++ ++ if (wrqu->retry.flags & IW_RETRY_LIFETIME || ++ wrqu->retry.disabled){ ++ err = -EINVAL; ++ goto exit; ++ } ++ if (!(wrqu->retry.flags & IW_RETRY_LIMIT)){ ++ err = -EINVAL; ++ goto exit; ++ } ++ ++ if(wrqu->retry.value > R8180_MAX_RETRY){ ++ err= -EINVAL; ++ goto exit; ++ } ++ if (wrqu->retry.flags & IW_RETRY_MAX) { ++ priv->retry_rts = wrqu->retry.value; ++ DMESG("Setting retry for RTS/CTS data to %d", wrqu->retry.value); ++ ++ }else { ++ priv->retry_data = wrqu->retry.value; ++ DMESG("Setting retry for non RTS/CTS data to %d", wrqu->retry.value); ++ } ++ ++ /* FIXME ! ++ * We might try to write directly the TX config register ++ * or to restart just the (R)TX process. ++ * I'm unsure if whole reset is really needed ++ */ ++ ++ rtl8180_commit(dev); ++ /* ++ if(priv->up){ ++ rtl8180_rtx_disable(dev); ++ rtl8180_rx_enable(dev); ++ rtl8180_tx_enable(dev); ++ ++ } ++ */ ++exit: ++ up(&priv->wx_sem); ++ ++ return err; ++} ++ ++static int r8180_wx_get_retry(struct net_device *dev, ++ struct iw_request_info *info, ++ union iwreq_data *wrqu, char *extra) ++{ ++ struct r8180_priv *priv = ieee80211_priv(dev); ++ ++ ++ wrqu->retry.disabled = 0; /* can't be disabled */ ++ ++ if ((wrqu->retry.flags & IW_RETRY_TYPE) == ++ IW_RETRY_LIFETIME) ++ return -EINVAL; ++ ++ if (wrqu->retry.flags & IW_RETRY_MAX) { ++ wrqu->retry.flags = IW_RETRY_LIMIT & IW_RETRY_MAX; ++ wrqu->retry.value = priv->retry_rts; ++ } else { ++ wrqu->retry.flags = IW_RETRY_LIMIT & IW_RETRY_MIN; ++ wrqu->retry.value = priv->retry_data; ++ } ++ //DMESG("returning %d",wrqu->retry.value); ++ ++ ++ return 0; ++} ++ ++static int r8180_wx_get_sens(struct net_device *dev, ++ struct iw_request_info *info, ++ union iwreq_data *wrqu, char *extra) ++{ ++ struct r8180_priv *priv = ieee80211_priv(dev); ++ if(priv->rf_set_sens == NULL) ++ return -1; /* we have not this support for this radio */ ++ wrqu->sens.value = priv->sens; ++ return 0; ++} ++ ++ ++static int r8180_wx_set_sens(struct net_device *dev, ++ struct iw_request_info *info, ++ union iwreq_data *wrqu, char *extra) ++{ ++ ++ struct r8180_priv *priv = ieee80211_priv(dev); ++ ++ short err = 0; ++ ++ if(priv->ieee80211->bHwRadioOff) ++ return 0; ++ ++ down(&priv->wx_sem); ++ //DMESG("attempt to set sensivity to %ddb",wrqu->sens.value); ++ if(priv->rf_set_sens == NULL) { ++ err= -1; /* we have not this support for this radio */ ++ goto exit; ++ } ++ if(priv->rf_set_sens(dev, wrqu->sens.value) == 0) ++ priv->sens = wrqu->sens.value; ++ else ++ err= -EINVAL; ++ ++exit: ++ up(&priv->wx_sem); ++ ++ return err; ++} ++ ++ ++static int dummy(struct net_device *dev, struct iw_request_info *a, ++ union iwreq_data *wrqu,char *b) ++{ ++ return -1; ++} ++static int r8180_wx_set_enc_ext(struct net_device *dev, ++ struct iw_request_info *info, ++ union iwreq_data *wrqu, char *extra) ++{ ++ ++ struct r8180_priv *priv = ieee80211_priv(dev); ++ //printk("===>%s()\n", __FUNCTION__); ++ ++ int ret=0; ++ ++ if(priv->ieee80211->bHwRadioOff) ++ return 0; ++ ++ down(&priv->wx_sem); ++ ret = ieee80211_wx_set_encode_ext(priv->ieee80211, info, wrqu, extra); ++ up(&priv->wx_sem); ++ return ret; ++ ++} ++static int r8180_wx_set_auth(struct net_device *dev, ++ struct iw_request_info *info, ++ union iwreq_data* data, char *extra) ++{ ++ //printk("====>%s()\n", __FUNCTION__); ++ struct r8180_priv *priv = ieee80211_priv(dev); ++ int ret=0; ++ ++ if(priv->ieee80211->bHwRadioOff) ++ return 0; ++ ++ down(&priv->wx_sem); ++ ret = ieee80211_wx_set_auth(priv->ieee80211, info, &(data->param), extra); ++ up(&priv->wx_sem); ++ return ret; ++} ++ ++static int r8180_wx_set_mlme(struct net_device *dev, ++ struct iw_request_info *info, ++ union iwreq_data *wrqu, char *extra) ++{ ++ //printk("====>%s()\n", __FUNCTION__); ++ ++ int ret=0; ++ struct r8180_priv *priv = ieee80211_priv(dev); ++ ++ if(priv->ieee80211->bHwRadioOff) ++ return 0; ++ ++ down(&priv->wx_sem); ++#if 1 ++ ret = ieee80211_wx_set_mlme(priv->ieee80211, info, wrqu, extra); ++#endif ++ up(&priv->wx_sem); ++ return ret; ++} ++ ++static int r8180_wx_set_gen_ie(struct net_device *dev, ++ struct iw_request_info *info, ++ union iwreq_data* data, char *extra) ++{ ++ //printk("====>%s(), len:%d\n", __FUNCTION__, data->length); ++ int ret=0; ++ struct r8180_priv *priv = ieee80211_priv(dev); ++ ++ if(priv->ieee80211->bHwRadioOff) ++ return 0; ++ ++ down(&priv->wx_sem); ++#if 1 ++ ret = ieee80211_wx_set_gen_ie(priv->ieee80211, extra, data->data.length); ++#endif ++ up(&priv->wx_sem); ++ //printk("<======%s(), ret:%d\n", __FUNCTION__, ret); ++ return ret; ++ ++ ++} ++ ++#ifdef _RTL8187_EXT_PATCH_ ++/* ++ Output: ++ (case 1) Mesh: Enable. MESHID=[%s] (max length of %s is 32 bytes). ++ (case 2) Mesh: Disable. ++*/ ++static int r8180_wx_get_meshinfo(struct net_device *dev, ++ struct iw_request_info *info, ++ union iwreq_data *wrqu, char *extra) ++{ ++ struct r8180_priv *priv = ieee80211_priv(dev); ++ ++ if( ! priv->mshobj || !priv->mshobj->ext_patch_r8180_wx_get_meshinfo ) ++ return 0; ++ return priv->mshobj->ext_patch_r8180_wx_get_meshinfo(dev, info, wrqu, extra); ++} ++ ++ ++static int r8180_wx_enable_mesh(struct net_device *dev, ++ struct iw_request_info *info, ++ union iwreq_data *wrqu, char *extra) ++{ ++ struct r8180_priv *priv = ieee80211_priv(dev); ++ struct ieee80211_device *ieee = priv->ieee80211; ++ ++ int ret = 0; ++ ++ if( ! priv->mshobj || !priv->mshobj->ext_patch_r8180_wx_enable_mesh ) ++ return 0; ++ ++ down(&priv->wx_sem); ++ if(priv->mshobj->ext_patch_r8180_wx_enable_mesh(dev)) ++ { ++ union iwreq_data tmprqu; ++ tmprqu.mode = ieee->iw_mode; ++ ieee->iw_mode = 0; ++ ret = ieee80211_wx_set_mode(ieee, info, &tmprqu, extra); ++ rtl8187_set_rxconf(dev); ++ } ++ ++ up(&priv->wx_sem); ++ ++ return ret; ++ ++} ++ ++static int r8180_wx_disable_mesh(struct net_device *dev, ++ struct iw_request_info *info, ++ union iwreq_data *wrqu, char *extra) ++{ ++ struct r8180_priv *priv = ieee80211_priv(dev); ++ struct ieee80211_device *ieee = priv->ieee80211; ++ ++ int ret = 0; ++ ++ if( ! priv->mshobj || !priv->mshobj->ext_patch_r8180_wx_disable_mesh ) ++ return 0; ++ ++ down(&priv->wx_sem); ++ if(priv->mshobj->ext_patch_r8180_wx_disable_mesh(dev)) ++ { ++ union iwreq_data tmprqu; ++ tmprqu.mode = ieee->iw_mode; ++ ieee->iw_mode = 999; ++ ret = ieee80211_wx_set_mode(ieee, info, &tmprqu, extra); ++ rtl8187_set_rxconf(dev); ++ } ++ ++ up(&priv->wx_sem); ++ ++ return ret; ++} ++ ++ ++int r8180_wx_set_channel(struct net_device *dev, ++ struct iw_request_info *info, ++ union iwreq_data *wrqu, char *extra) ++{ ++ int ch = *extra; ++ struct r8180_priv *priv = ieee80211_priv(dev); ++ struct ieee80211_device *ieee = priv->ieee80211; ++ ++ if(priv->ieee80211->bHwRadioOff) ++ return 0; ++ ++ // is 11s ? ++ if (!priv->mshobj || (ieee->iw_mode != ieee->iw_ext_mode) || !priv->mshobj->ext_patch_r8180_wx_set_channel ) ++ return 0; ++ ++ printk("set channel = %d\n", ch); ++ if ( ch < 0 ) ++ { ++ ieee80211_start_scan(ieee); // auto ++ ieee->meshScanMode =2; ++ } ++ else ++ { ++//#ifdef NETWORKMANAGER_UI ++ if((priv->ieee80211->iw_mode == IW_MODE_MESH) && (priv->ieee80211->iw_ext_mode == IW_MODE_MESH)){ ++ } ++//#else ++ else{ ++ down(&priv->wx_sem);} ++//#endif ++ ieee->meshScanMode =0; ++ // ieee->set_chan(dev, ch); ++//#ifdef _RTL8187_EXT_PATCH_ ++ if(priv->mshobj->ext_patch_r8180_wx_set_channel) ++ { ++ priv->mshobj->ext_patch_r8180_wx_set_channel(ieee, ch); ++ priv->mshobj->ext_patch_r8180_wx_set_mesh_chan(dev,ch); ++ } ++//#endif ++ ieee->set_chan(ieee->dev, ch); ++ ieee->current_network.channel = ch; ++ queue_work(ieee->wq, &ieee->ext_stop_scan_wq); ++ ieee80211_ext_send_11s_beacon(ieee); ++//#ifdef NETWORKMANAGER_UI ++ if((priv->ieee80211->iw_mode == IW_MODE_MESH) && (priv->ieee80211->iw_ext_mode == IW_MODE_MESH)){ ++ } ++//#else ++ else{ ++ up(&priv->wx_sem);} ++//#endif ++ //up(&ieee->wx_sem); ++ ++ // ieee80211_stop_scan(ieee); // user set ++ // ++ ++ /* ++ netif_carrier_off(ieee->dev); ++ ++ if (ieee->data_hard_stop) ++ ieee->data_hard_stop(ieee->dev); ++ ++ ieee->state = IEEE80211_NOLINK; ++ ieee->link_change(ieee->dev); ++ ++ ieee->current_network.channel = fwrq->m; ++ ieee->set_chan(ieee->dev, ieee->current_network.channel); ++ ++ ++ if (ieee->data_hard_resume) ++ ieee->data_hard_resume(ieee->dev); ++ ++ netif_carrier_on(ieee->dev); ++ */ ++ ++ } ++ ++ return 0; ++} ++ ++static int r8180_wx_set_meshID(struct net_device *dev, ++ struct iw_request_info *info, ++ union iwreq_data *wrqu, char *extra) ++{ ++ struct r8180_priv *priv = ieee80211_priv(dev); ++ ++ if(priv->ieee80211->bHwRadioOff) ++ return 0; ++ ++ if( ! priv->mshobj || !priv->mshobj->ext_patch_r8180_wx_set_meshID ) ++ return 0; ++ ++ //printk("len=%d\n", wrqu->data.length); ++ //printk("\nCall setMeshid."); ++ return priv->mshobj->ext_patch_r8180_wx_set_meshID(dev, wrqu->data.pointer); ++} ++ ++ ++/* reserved for future ++static int r8180_wx_add_mac_allow(struct net_device *dev, ++ struct iw_request_info *info, ++ union iwreq_data *wrqu, char *extra) ++{ ++ struct r8180_priv *priv = ieee80211_priv(dev); ++ ++ if( ! priv->mshobj || !priv->mshobj->ext_patch_r8180_wx_set_add_mac_allow ) ++ return 0; ++ ++ return priv->mshobj->ext_patch_r8180_wx_set_add_mac_allow(dev, info, wrqu, extra); ++} ++ ++static int r8180_wx_del_mac_allow(struct net_device *dev, ++ struct iw_request_info *info, ++ union iwreq_data *wrqu, char *extra) ++{ ++ struct r8180_priv *priv = ieee80211_priv(dev); ++ ++ if( ! priv->mshobj || !priv->mshobj->ext_patch_r8180_wx_set_del_mac_allow ) ++ return 0; ++ ++ return priv->mshobj->ext_patch_r8180_wx_set_del_mac_allow(dev, info, wrqu, extra); ++} ++*/ ++static int r8180_wx_add_mac_deny(struct net_device *dev, ++ struct iw_request_info *info, ++ union iwreq_data *wrqu, char *extra) ++{ ++ struct r8180_priv *priv = ieee80211_priv(dev); ++ ++ if( ! priv->mshobj || !priv->mshobj->ext_patch_r8180_wx_set_add_mac_deny ) ++ return 0; ++ ++ return priv->mshobj->ext_patch_r8180_wx_set_add_mac_deny(dev, info, wrqu, extra); ++} ++ ++static int r8180_wx_del_mac_deny(struct net_device *dev, ++ struct iw_request_info *info, ++ union iwreq_data *wrqu, char *extra) ++{ ++ struct r8180_priv *priv = ieee80211_priv(dev); ++ ++ if( ! priv->mshobj || !priv->mshobj->ext_patch_r8180_wx_set_del_mac_deny ) ++ return 0; ++ ++ return priv->mshobj->ext_patch_r8180_wx_set_del_mac_deny(dev, info, wrqu, extra); ++} ++ ++/* reserved for future ++static int r8180_wx_get_mac_allow(struct net_device *dev, ++ struct iw_request_info *info, ++ union iwreq_data *wrqu, char *extra) ++{ ++ struct r8180_priv *priv = ieee80211_priv(dev); ++ ++ if( ! priv->mshobj || !priv->mshobj->ext_patch_r8180_wx_get_mac_allow ) ++ return 0; ++ ++ return priv->mshobj->ext_patch_r8180_wx_get_mac_allow(dev, info, wrqu, extra); ++} ++*/ ++ ++static int r8180_wx_get_mac_deny(struct net_device *dev, ++ struct iw_request_info *info, ++ union iwreq_data *wrqu, char *extra) ++{ ++ struct r8180_priv *priv = ieee80211_priv(dev); ++ ++ if( ! priv->mshobj || !priv->mshobj->ext_patch_r8180_wx_get_mac_deny ) ++ return 0; ++ ++ return priv->mshobj->ext_patch_r8180_wx_get_mac_deny(dev, info, wrqu, extra); ++} ++ ++ ++static int r8180_wx_get_mesh_list(struct net_device *dev, ++ struct iw_request_info *info, ++ union iwreq_data *wrqu, char *extra) ++{ ++ struct r8180_priv *priv = ieee80211_priv(dev); ++ ++ if( ! priv->mshobj || !priv->mshobj->ext_patch_r8180_wx_get_mesh_list ) ++ return 0; ++ ++ return priv->mshobj->ext_patch_r8180_wx_get_mesh_list(dev, info, wrqu, extra); ++} ++ ++static int r8180_wx_mesh_scan(struct net_device *dev, ++ struct iw_request_info *info, ++ union iwreq_data *wrqu, char *extra) ++{ ++ struct r8180_priv *priv = ieee80211_priv(dev); ++ ++ if( ! priv->mshobj || !priv->mshobj->ext_patch_r8180_wx_mesh_scan ) ++ return 0; ++ ++ return priv->mshobj->ext_patch_r8180_wx_mesh_scan(dev, info, wrqu, extra); ++} ++ ++static int r8180_wx_join_mesh(struct net_device *dev, ++ struct iw_request_info *info, ++ union iwreq_data *wrqu, char *extra) ++{ ++ struct r8180_priv *priv = ieee80211_priv(dev); ++ int index; ++ int ret=0; ++ char extmeshid[32]; ++ int len=0; ++ char id[50], ch; ++//#ifdef NETWORKMANAGER_UI ++ ++ if((priv->ieee80211->iw_mode == IW_MODE_MESH) && (priv->ieee80211->iw_ext_mode == IW_MODE_MESH)){ ++ printk("join mesh %s\n",extra); ++ if (wrqu->essid.length > IW_ESSID_MAX_SIZE){ ++ ret= -E2BIG; ++ goto out; ++ } ++ //printk("wrqu->essid.length is %d\n",wrqu->essid.length); ++ //printk("wrqu->essid.flags is %d\n",wrqu->essid.flags); ++ if((wrqu->essid.length == 1) && (wrqu->essid.flags == 1)){ ++ ret = 0; ++ goto out; ++ } ++ if (wrqu->essid.flags && wrqu->essid.length) { ++ if(priv->mshobj->ext_patch_r8180_wx_get_selected_mesh_channel(dev, extra, &ch)) ++ { ++ priv->mshobj->ext_patch_r8180_wx_set_meshID(dev, extra); ++ priv->mshobj->ext_patch_r8180_wx_set_mesh_chan(dev,ch); ++ r8180_wx_set_channel(dev, NULL, NULL, &ch); ++ } ++ else ++ printk("invalid mesh #\n"); ++ ++ } ++#if 0 ++ else{ ++ if(priv->mshobj->ext_patch_r8180_wx_get_selected_mesh_channel(dev, 0, &ch)) ++ { ++ priv->mshobj->ext_patch_r8180_wx_set_meshID(dev, extra); ++ priv->mshobj->ext_patch_r8180_wx_set_mesh_chan(dev,ch); ++ r8180_wx_set_channel(dev, NULL, NULL, &ch); ++ } ++ else ++ printk("invalid mesh #\n"); ++ ++ } ++#endif ++ } ++ else{ ++//#else ++ index = *(extra); ++// printk("index=%d\n", index); ++ ++ if( ! priv->mshobj ++ || !priv->mshobj->ext_patch_r8180_wx_set_meshID ++ || !priv->mshobj->ext_patch_r8180_wx_get_selected_mesh ) ++ return 0; ++ ++ if( priv->mshobj->ext_patch_r8180_wx_get_selected_mesh(dev, index, &ch, id) ) ++ { ++ // printk("ch=%d, id=%s\n", ch, id); ++ priv->mshobj->ext_patch_r8180_wx_set_meshID(dev, id); ++ priv->mshobj->ext_patch_r8180_wx_set_mesh_chan(dev,ch); ++ r8180_wx_set_channel(dev, NULL, NULL, &ch); ++ } ++ else ++ printk("invalid mesh #\n"); ++ } ++//#endif ++out: ++ return ret; ++} ++ ++#endif // _RTL8187_EXT_PATCH_ ++ ++ ++static int r8180_wx_get_radion(struct net_device *dev, ++ struct iw_request_info *info, ++ union iwreq_data *wrqu, char *extra) ++{ ++ struct r8180_priv *priv = ieee80211_priv(dev); ++// u8 addr; ++ ++ down(&priv->wx_sem); ++ if(priv->radion == 1) { ++ *(int *)extra = 1; ++ } else { ++ ++ *(int *)extra = 0; ++ } ++ up(&priv->wx_sem); ++ return 0; ++ ++} ++ ++static int r8180_wx_set_radion(struct net_device *dev, ++ struct iw_request_info *info, ++ union iwreq_data *wrqu, char *extra) ++{ ++ int radion = *extra; ++ struct r8180_priv *priv = ieee80211_priv(dev); ++// struct ieee80211_device *ieee = priv->ieee80211; ++ u8 btCR9346, btConfig3; ++ int i; ++ u16 u2bTFPC = 0; ++ u8 u1bTmp; ++ ++ if(priv->ieee80211->bHwRadioOff) ++ return 0; ++ ++ down(&priv->wx_sem); ++ printk("set radion = %d\n", radion); ++ ++#ifdef _RTL8187_EXT_PATCH_ ++ if(ieee->iw_mode == ieee->iw_ext_mode) { ++ printk("mesh mode:: could not set radi on/off = %d\n", radion); ++ up(&priv->wx_sem); ++ return 0; ++ } ++#endif ++ // Set EEM0 and EEM1 in 9346CR. ++ btCR9346 = read_nic_byte(dev, CR9346); ++ write_nic_byte(dev, CR9346, (btCR9346|0xC0) ); ++ // Set PARM_En in Config3. ++ btConfig3 = read_nic_byte(dev, CONFIG3); ++ write_nic_byte(dev, CONFIG3, (btConfig3|CONFIG3_PARM_En) ); ++ ++ if ( radion == 1) //radion off ++ { ++ printk("==================>RF on\n"); ++ write_nic_dword(dev, ANAPARAM, ANAPARM_ON); ++ write_nic_dword(dev, ANAPARAM2, ANAPARM2_ON); ++ write_nic_byte(dev, CONFIG4, (priv->RFProgType)); ++ ++ write_nic_byte(dev, 0x085, 0x24); // 061219, SD3 ED: for minicard CCK power leakage issue. ++ write_rtl8225(dev, 0x4, 0x9FF); ++ ++ u1bTmp = read_nic_byte(dev, 0x24E); ++ write_nic_byte(dev, 0x24E, (u1bTmp & (~(BIT5|BIT6))) );// 070124 SD1 Alex: turn on CCK and OFDM. ++ priv->radion = 1; //radion on ++ } ++ else ++ { ++ printk("==================>RF off\n"); ++ for(i = 0; i < MAX_DOZE_WAITING_TIMES_87B; i++) ++ { // Make sure TX FIFO is empty befor turn off RFE pwoer. ++ u2bTFPC = read_nic_word(dev, TFPC); ++ if(u2bTFPC == 0) ++ { ++ break; ++ } ++ else ++ { ++ printk("%d times TFPC: %d != 0 before doze!\n", (i+1), u2bTFPC); ++ udelay(10); ++ } ++ } ++ if( i == MAX_DOZE_WAITING_TIMES_87B ) ++ { ++ printk("\n\n\n SetZebraRFPowerState8187B(): %d times TFPC: %d != 0 !!!\n\n\n",\ ++ MAX_DOZE_WAITING_TIMES_87B, u2bTFPC); ++ } ++ ++ u1bTmp = read_nic_byte(dev, 0x24E); ++ write_nic_byte(dev, 0x24E, (u1bTmp|BIT5|BIT6));// 070124 SD1 Alex: turn off CCK and OFDM. ++ ++ write_rtl8225(dev, 0x4,0x1FF); // Turn off RF first to prevent BB lock up, suggested by PJ, 2006.03.03. ++ write_nic_byte(dev, 0x085, 0x04); // 061219, SD3 ED: for minicard CCK power leakage issue. ++ ++ write_nic_byte(dev, CONFIG4, (priv->RFProgType|Config4_PowerOff)); ++ ++ write_nic_dword(dev, ANAPARAM, ANAPARM_OFF); ++ write_nic_dword(dev, ANAPARAM2, ANAPARM2_OFF); // 070301, SD1 William: to reduce RF off power consumption to 80 mA. ++ priv->radion = 0; //radion off ++ } ++ // Clear PARM_En in Config3. ++ btConfig3 &= ~(CONFIG3_PARM_En); ++ write_nic_byte(dev, CONFIG3, btConfig3); ++ // Clear EEM0 and EEM1 in 9346CR. ++ btCR9346 &= ~(0xC0); ++ write_nic_byte(dev, CR9346, btCR9346); ++ ++ up(&priv->wx_sem); ++ ++ return 0; ++} ++ ++static int r8180_wx_set_ratadpt (struct net_device *dev, ++ struct iw_request_info *info, ++ union iwreq_data *wrqu, char *extra) ++{ ++ int ratadapt = *extra; ++ struct r8180_priv *priv = ieee80211_priv(dev); ++ struct ieee80211_device *ieee = priv->ieee80211; ++ ++ if(priv->ieee80211->bHwRadioOff) ++ return 0; ++ ++ down(&priv->wx_sem); ++ printk("Set rate adaptive %s\n", (ratadapt==0)?"on":"off"); ++ if(ratadapt == 0) { ++ del_timer_sync(&priv->rateadapter_timer); ++ cancel_delayed_work(&priv->ieee80211->rate_adapter_wq); ++ priv->rateadapter_timer.function((unsigned long)dev); ++ } else { ++ del_timer_sync(&priv->rateadapter_timer); ++ cancel_delayed_work(&priv->ieee80211->rate_adapter_wq); ++ printk("force rate to %d\n", ratadapt); ++ ieee->rate = ratadapt; ++ } ++ up(&priv->wx_sem); ++ return 0; ++} ++ ++#ifdef ENABLE_TOSHIBA_CONFIG ++static int r8180_wx_get_tblidx(struct net_device *dev, ++ struct iw_request_info *info, ++ union iwreq_data *wrqu, char *extra) ++{ ++ struct r8180_priv *priv = ieee80211_priv(dev); ++ //extern u8 chan_plan_index; ++ //printk("=========>%s(), %x\n", __FUNCTION__, priv->channel_plan); ++ down(&priv->wx_sem); ++ put_user(priv->channel_plan, (u8*)wrqu->data.pointer); ++ up(&priv->wx_sem); ++ return 0; ++ ++} ++ ++//This func will be called after probe auto ++static int r8180_wx_set_tbl (struct net_device *dev, ++ struct iw_request_info *info, ++ union iwreq_data *wrqu, char *extra) ++{ ++ struct r8180_priv *priv = ieee80211_priv(dev); ++ u8 len = 0; ++ s8 err = -1; ++ extern CHANNEL_LIST Current_tbl; ++ down(&priv->wx_sem); ++ if (!wrqu->data.pointer) ++ { ++ printk("user data pointer is null\n"); ++ goto exit; ++ } ++ len = wrqu->data.length; ++ //printk("=========>%s(), len:%d\n", __FUNCTION__, len); ++ //memset(&Current_tbl, 0, sizeof(CHANNEL_LIST)); ++ if (copy_from_user((u8*)&Current_tbl, (void*)wrqu->data.pointer, len)) ++ { ++ printk("error copy from user\n"); ++ goto exit; ++ } ++ { ++ int i; ++ Current_tbl.Len = len; ++ //printk("%d\n", Current_tbl.Len); ++ ++ Dot11d_Init(priv->ieee80211); ++ priv->ieee80211->bGlobalDomain = false; ++ priv->ieee80211->bWorldWide13 = false; ++ ++ //lzm add 081205 ++ priv->ieee80211->MinPassiveChnlNum=12; ++ priv->ieee80211->IbssStartChnl= 10; ++ ++ for (i=0; i<Current_tbl.Len; i++){ ++ //printk("%2d ", Current_tbl.Channel[i]); ++ if(priv->channel_plan == COUNTRY_CODE_ETSI) ++ { ++ if(Current_tbl.Channel[i] <= 11) ++ { ++#ifdef ENABLE_DOT11D ++ GET_DOT11D_INFO(priv->ieee80211)->channel_map[Current_tbl.Channel[i]] = 1; ++#else ++ priv->ieee80211->channel_map[Current_tbl.Channel[i]] = 1; ++#endif ++ } ++ else if((Current_tbl.Channel[i] >= 11) && (Current_tbl.Channel[i] <= 13)) ++ { ++#ifdef ENABLE_DOT11D ++ GET_DOT11D_INFO(priv->ieee80211)->channel_map[Current_tbl.Channel[i]] = 2; ++#else ++ priv->ieee80211->channel_map[Current_tbl.Channel[i]] = 2; ++#endif ++ } ++ } ++ else ++ { ++ if(Current_tbl.Channel[i] <= 14) ++ { ++#ifdef ENABLE_DOT11D ++ GET_DOT11D_INFO(priv->ieee80211)->channel_map[Current_tbl.Channel[i]] = 1; ++#else ++ priv->ieee80211->channel_map[Current_tbl.Channel[i]] = 1; ++#endif ++ } ++ } ++ } ++#if 0 ++ printk("\n"); ++ for(i=1; i<MAX_CHANNEL_NUMBER; i++) ++ { ++#ifdef ENABLE_DOT11D ++ printk("%2d ", GET_DOT11D_INFO(priv->ieee80211)->channel_map[i]); ++#else ++ printk("%2d ", priv->ieee80211->channel_map[i]); ++#endif ++ } ++ printk("\n"); ++ ++#endif ++ if(priv->ieee80211->proto_started) ++ {//we need to restart protocol now if it was start before channel map ++ ieee80211_softmac_stop_protocol(priv->ieee80211); ++ //mdelay(1); ++ ieee80211_softmac_start_protocol(priv->ieee80211); ++ } ++ } ++ err = 0; ++exit: ++ up(&priv->wx_sem); ++ return err; ++ ++ ++} ++ ++#endif ++ ++ ++static iw_handler r8180_wx_handlers[] = ++{ ++ NULL, /* SIOCSIWCOMMIT */ ++ r8180_wx_get_name, /* SIOCGIWNAME */ ++ dummy, /* SIOCSIWNWID */ ++ dummy, /* SIOCGIWNWID */ ++ r8180_wx_set_freq, /* SIOCSIWFREQ */ ++ r8180_wx_get_freq, /* SIOCGIWFREQ */ ++ r8180_wx_set_mode, /* SIOCSIWMODE */ ++ r8180_wx_get_mode, /* SIOCGIWMODE */ ++ r8180_wx_set_sens, /* SIOCSIWSENS */ ++ r8180_wx_get_sens, /* SIOCGIWSENS */ ++ NULL, /* SIOCSIWRANGE */ ++ rtl8180_wx_get_range, /* SIOCGIWRANGE */ ++ NULL, /* SIOCSIWPRIV */ ++ NULL, /* SIOCGIWPRIV */ ++ NULL, /* SIOCSIWSTATS */ ++ NULL, /* SIOCGIWSTATS */ ++ dummy, /* SIOCSIWSPY */ ++ dummy, /* SIOCGIWSPY */ ++ NULL, /* SIOCGIWTHRSPY */ ++ NULL, /* SIOCWIWTHRSPY */ ++ r8180_wx_set_wap, /* SIOCSIWAP */ ++ r8180_wx_get_wap, /* SIOCGIWAP */ ++ r8180_wx_set_mlme, //NULL, /* SIOCSIWMLME*/ /* -- hole -- */ ++ dummy, /* SIOCGIWAPLIST -- depricated */ ++ r8180_wx_set_scan, /* SIOCSIWSCAN */ ++ r8180_wx_get_scan, /* SIOCGIWSCAN */ ++ r8180_wx_set_essid, /* SIOCSIWESSID */ ++ r8180_wx_get_essid, /* SIOCGIWESSID */ ++ dummy, /* SIOCSIWNICKN */ ++ dummy, /* SIOCGIWNICKN */ ++ NULL, /* -- hole -- */ ++ NULL, /* -- hole -- */ ++ r8180_wx_set_rate, /* SIOCSIWRATE */ ++ r8180_wx_get_rate, /* SIOCGIWRATE */ ++ dummy, /* SIOCSIWRTS */ ++ dummy, /* SIOCGIWRTS */ ++ r8180_wx_set_frag, /* SIOCSIWFRAG */ ++ r8180_wx_get_frag, /* SIOCGIWFRAG */ ++ dummy, /* SIOCSIWTXPOW */ ++ dummy, /* SIOCGIWTXPOW */ ++ r8180_wx_set_retry, /* SIOCSIWRETRY */ ++ r8180_wx_get_retry, /* SIOCGIWRETRY */ ++ r8180_wx_set_enc, /* SIOCSIWENCODE */ ++ r8180_wx_get_enc, /* SIOCGIWENCODE */ ++ dummy, /* SIOCSIWPOWER */ ++ dummy, /* SIOCGIWPOWER */ ++ NULL, /*---hole---*/ ++ NULL, /*---hole---*/ ++ r8180_wx_set_gen_ie,//NULL, /* SIOCSIWGENIE */ ++ NULL, /* SIOCSIWGENIE */ ++ r8180_wx_set_auth,//NULL, /* SIOCSIWAUTH */ ++ NULL,//r8180_wx_get_auth,//NULL, /* SIOCSIWAUTH */ ++ r8180_wx_set_enc_ext, /* SIOCSIWENCODEEXT */ ++ NULL,//r8180_wx_get_enc_ext,//NULL, /* SIOCSIWENCODEEXT */ ++ NULL, /* SIOCSIWPMKSA */ ++ NULL, /*---hole---*/ ++}; ++ ++ ++static const struct iw_priv_args r8180_private_args[] = { ++ { ++ SIOCIWFIRSTPRIV + 0x0, ++ IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "badcrc" ++ }, ++ ++ { ++ SIOCIWFIRSTPRIV + 0x1, ++ IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "activescan" ++ ++ }, ++ { ++ SIOCIWFIRSTPRIV + 0x2, ++ IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "rawtx" ++ }, ++#ifdef JOHN_IOCTL ++ { ++ SIOCIWFIRSTPRIV + 0x3, ++ IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "readRF" ++ } ++ , ++ { ++ SIOCIWFIRSTPRIV + 0x4, ++ IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "writeRF" ++ } ++ , ++ { ++ SIOCIWFIRSTPRIV + 0x5, ++ IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "readBB" ++ } ++ , ++ { ++ SIOCIWFIRSTPRIV + 0x6, ++ IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "writeBB" ++ } ++ , ++ { ++ SIOCIWFIRSTPRIV + 0x7, ++ IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "readnicb" ++ } ++ , ++ { ++ SIOCIWFIRSTPRIV + 0x8, ++ IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "writenicb" ++ } ++ , ++ { ++ SIOCIWFIRSTPRIV + 0x9, ++ IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "apinfo" ++ }, ++#endif ++ { ++ SIOCIWFIRSTPRIV + 0xA, ++ 0, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED |1, "getradion" ++ }, ++ { ++ SIOCIWFIRSTPRIV + 0xB, ++ IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "setradion" ++ }, ++ { ++ SIOCIWFIRSTPRIV + 0xC, ++ IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "ratadpt" ++ }, ++#ifdef ENABLE_TOSHIBA_CONFIG ++ { ++ SIOCIWFIRSTPRIV + 0xD, ++ 0, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, "gettblidx" ++ }, ++ { ++ SIOCIWFIRSTPRIV + 0xE, ++ IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1,0, "settblidx" ++ }, ++ ++#endif ++ ++}; ++ ++/* ++ * Private ioctl interface information ++ ++struct iw_priv_args ++{ ++// __u32 cmd; ++// __u16 set_args; ++// __u16 get_args; ++// char name[IFNAMSIZ]; ++//}; ++*/ ++//If get cmd's number is big,there may cause some problemes. ++//So modified by Lawrence,071120 ++ ++static iw_handler r8180_private_handler[] = { ++// r8180_wx_set_monitor, /* SIOCIWFIRSTPRIV */ ++ r8180_wx_set_crcmon, /*SIOCIWSECONDPRIV*/ ++// r8180_wx_set_forceassociate, ++// r8180_wx_set_beaconinterval, ++// r8180_wx_set_monitor_type, ++ r8180_wx_set_scan_type, ++ r8180_wx_set_rawtx, ++ ++#if 0 ++#ifdef _RTL8187_EXT_PATCH_ ++ r8180_wx_get_meshinfo, ++ r8180_wx_enable_mesh, ++ r8180_wx_disable_mesh, ++ r8180_wx_set_channel, ++ r8180_wx_set_meshID, ++ ++// r8180_wx_add_mac_allow, ++// r8180_wx_get_mac_allow, ++// r8180_wx_del_mac_allow, ++ r8180_wx_add_mac_deny, ++ r8180_wx_get_mac_deny, ++ r8180_wx_del_mac_deny, ++ r8180_wx_get_mesh_list, ++ r8180_wx_mesh_scan, ++ r8180_wx_join_mesh, ++#endif ++#endif ++ ++#ifdef JOHN_IOCTL ++ r8180_wx_read_regs, ++ r8180_wx_write_regs, ++ r8180_wx_read_bb, ++ r8180_wx_write_bb, ++ r8180_wx_read_nicb, ++ r8180_wx_write_nicb, ++ r8180_wx_get_ap_status, ++#endif ++ r8180_wx_get_radion, ++ r8180_wx_set_radion, ++ r8180_wx_set_ratadpt, ++#ifdef ENABLE_TOSHIBA_CONFIG ++ r8180_wx_get_tblidx, ++ r8180_wx_set_tbl, ++#endif ++}; ++ ++#if WIRELESS_EXT >= 17 ++//WB modefied to show signal to GUI on 18-01-2008 ++static struct iw_statistics *r8180_get_wireless_stats(struct net_device *dev) ++{ ++ struct r8180_priv *priv = ieee80211_priv(dev); ++ struct ieee80211_device* ieee = priv->ieee80211; ++ struct iw_statistics* wstats = &priv->wstats; ++// struct ieee80211_network* target = NULL; ++ int tmp_level = 0; ++ int tmp_qual = 0; ++ int tmp_noise = 0; ++// unsigned long flag; ++ ++ if (ieee->state < IEEE80211_LINKED) ++ { ++ wstats->qual.qual = 0; ++ wstats->qual.level = 0; ++ wstats->qual.noise = 0; ++ wstats->qual.updated = IW_QUAL_ALL_UPDATED | IW_QUAL_DBM; ++ return wstats; ++ } ++#if 0 ++ spin_lock_irqsave(&ieee->lock, flag); ++ list_for_each_entry(target, &ieee->network_list, list) ++ { ++ if (is_same_network(target, &ieee->current_network)) ++ { ++ printk("it's same network:%s\n", target->ssid); ++#if 0 ++ if (!tmp_level) ++ { ++ tmp_level = target->stats.signalstrength; ++ tmp_qual = target->stats.signal; ++ } ++ else ++ { ++ ++ tmp_level = (15*tmp_level + target->stats.signalstrength)/16; ++ tmp_qual = (15*tmp_qual + target->stats.signal)/16; ++ } ++#else ++ tmp_level = target->stats.signal; ++ tmp_qual = target->stats.signalstrength; ++ tmp_noise = target->stats.noise; ++ printk("level:%d, qual:%d, noise:%d\n", tmp_level, tmp_qual, tmp_noise); ++#endif ++ break; ++ } ++ } ++ spin_unlock_irqrestore(&ieee->lock, flag); ++#endif ++ tmp_level = (&ieee->current_network)->stats.signal; ++ tmp_qual = (&ieee->current_network)->stats.signalstrength; ++ tmp_noise = (&ieee->current_network)->stats.noise; ++ //printk("level:%d, qual:%d, noise:%d\n", tmp_level, tmp_qual, tmp_noise); ++ ++ wstats->qual.level = tmp_level; ++ wstats->qual.qual = tmp_qual; ++ wstats->qual.noise = tmp_noise; ++ wstats->qual.updated = IW_QUAL_ALL_UPDATED| IW_QUAL_DBM; ++ return wstats; ++} ++#endif ++ ++ ++struct iw_handler_def r8180_wx_handlers_def={ ++ .standard = r8180_wx_handlers, ++ .num_standard = sizeof(r8180_wx_handlers) / sizeof(iw_handler), ++ .private = r8180_private_handler, ++ .num_private = sizeof(r8180_private_handler) / sizeof(iw_handler), ++ .num_private_args = sizeof(r8180_private_args) / sizeof(struct iw_priv_args), ++#if WIRELESS_EXT >= 17 ++ .get_wireless_stats = r8180_get_wireless_stats, ++#endif ++ .private_args = (struct iw_priv_args *)r8180_private_args, ++}; ++#ifdef _RTL8187_EXT_PATCH_ ++EXPORT_SYMBOL(r8180_wx_set_channel); ++#endif +diff -Nur linux-2.6.33/drivers/net/wireless/rtl8187b/r8180_wx.h linux-lemote/drivers/net/wireless/rtl8187b/r8180_wx.h +--- linux-2.6.33/drivers/net/wireless/rtl8187b/r8180_wx.h 1970-01-01 01:00:00.000000000 +0100 ++++ linux-lemote/drivers/net/wireless/rtl8187b/r8180_wx.h 2010-03-06 16:43:22.000000000 +0100 +@@ -0,0 +1,21 @@ ++/* ++ This is part of rtl8180 OpenSource driver - v 0.3 ++ Copyright (C) Andrea Merello 2004 <andreamrl@tiscali.it> ++ Released under the terms of GPL (General Public Licence) ++ ++ Parts of this driver are based on the GPL part of the official realtek driver ++ Parts of this driver are based on the rtl8180 driver skeleton from Patric Schenke & Andres Salomon ++ Parts of this driver are based on the Intel Pro Wireless 2100 GPL driver ++ ++ We want to tanks the Authors of such projects and the Ndiswrapper project Authors. ++*/ ++ ++/* this file (will) contains wireless extension handlers*/ ++ ++#ifndef R8180_WX_H ++#define R8180_WX_H ++#include <linux/wireless.h> ++#include "ieee80211/ieee80211.h" ++extern struct iw_handler_def r8180_wx_handlers_def; ++ ++#endif +diff -Nur linux-2.6.33/drivers/net/wireless/rtl8187b/r8187_core.c linux-lemote/drivers/net/wireless/rtl8187b/r8187_core.c +--- linux-2.6.33/drivers/net/wireless/rtl8187b/r8187_core.c 1970-01-01 01:00:00.000000000 +0100 ++++ linux-lemote/drivers/net/wireless/rtl8187b/r8187_core.c 2010-03-06 16:43:22.000000000 +0100 +@@ -0,0 +1,7042 @@ ++/* ++ This is part of rtl8187 OpenSource driver - v 0.1 ++ Copyright (C) Andrea Merello 2005 <andreamrl@tiscali.it> ++ Released under the terms of GPL (General Public License) ++ ++ ++ Parts of this driver are based on the rtl8180 driver skeleton ++ from Patric Schenke & Andres Salomon. ++ ++ Parts of this driver are based on the Intel Pro Wireless 2*00 GPL drivers. ++ ++ some ideas might be derived from David Young rtl8180 netbsd driver. ++ ++ Parts of the usb code are from the r8150.c driver in linux kernel ++ ++ Some ideas borrowed from the 8139too.c driver included in linux kernel. ++ ++ We (I?) want to thanks the Authors of those projecs and also the ++ Ndiswrapper's project Authors. ++ ++ A special big thanks goes also to Realtek corp. for their help in my ++ attempt to add RTL8187 and RTL8225 support, and to David Young also. ++ ++ - Please note that this file is a modified version from rtl8180-sa2400 ++ drv. So some other people have contributed to this project, and they are ++ thanked in the rtl8180-sa2400 CHANGELOG. ++*/ ++ ++#undef LOOP_TEST ++#undef DUMP_RX ++#undef DUMP_TX ++#undef DEBUG_TX_DESC2 ++#undef RX_DONT_PASS_UL ++#undef DEBUG_EPROM ++#undef DEBUG_RX_VERBOSE ++#undef DUMMY_RX ++#undef DEBUG_ZERO_RX ++#undef DEBUG_RX_SKB ++#undef DEBUG_TX_FRAG ++#undef DEBUG_RX_FRAG ++#undef DEBUG_TX_FILLDESC ++#undef DEBUG_TX ++#undef DEBUG_IRQ ++#undef DEBUG_RX ++#undef DEBUG_RXALLOC ++#undef DEBUG_REGISTERS ++#undef DEBUG_RING ++#undef DEBUG_IRQ_TASKLET ++#undef DEBUG_TX_ALLOC ++#undef DEBUG_TX_DESC ++#undef CONFIG_SOFT_BEACON ++#undef DEBUG_RW_REGISTER ++ ++#define CONFIG_RTL8180_IO_MAP ++//#define CONFIG_SOFT_BEACON ++//#define DEBUG_RW_REGISTER ++ ++#include "r8180_hw.h" ++#include "r8187.h" ++#include "r8180_rtl8225.h" /* RTL8225 Radio frontend */ ++#include "r8180_93cx6.h" /* Card EEPROM */ ++#include "r8180_wx.h" ++#include "r8180_dm.h" ++ ++#include <linux/dmapool.h> ++ ++#include <linux/usb.h> ++// FIXME: check if 2.6.7 is ok ++#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,7)) ++#define usb_kill_urb usb_unlink_urb ++#endif ++ ++#ifdef CONFIG_RTL8180_PM ++#include "r8180_pm.h" ++#endif ++ ++#ifdef ENABLE_DOT11D ++#include "dot11d.h" ++#endif ++ ++#ifndef USB_VENDOR_ID_REALTEK ++#define USB_VENDOR_ID_REALTEK 0x0bda ++#endif ++#ifndef USB_VENDOR_ID_NETGEAR ++#define USB_VENDOR_ID_NETGEAR 0x0846 ++#endif ++ ++#define TXISR_SELECT(priority) ((priority == MANAGE_PRIORITY)?rtl8187_managetx_isr:\ ++ (priority == BEACON_PRIORITY)?rtl8187_beacontx_isr: \ ++ (priority == VO_PRIORITY)?rtl8187_votx_isr: \ ++ (priority == VI_PRIORITY)?rtl8187_vitx_isr:\ ++ (priority == BE_PRIORITY)?rtl8187_betx_isr:rtl8187_bktx_isr) ++ ++static struct usb_device_id rtl8187_usb_id_tbl[] = { ++ {USB_DEVICE(USB_VENDOR_ID_REALTEK, 0x8187)}, ++ {USB_DEVICE(USB_VENDOR_ID_REALTEK, 0x8189)}, ++// {USB_DEVICE_VER(USB_VENDOR_ID_REALTEK, 0x8187,0x0200,0x0200)}, ++ {USB_DEVICE(USB_VENDOR_ID_NETGEAR, 0x6100)}, ++ {USB_DEVICE(USB_VENDOR_ID_NETGEAR, 0x6a00)}, ++ {USB_DEVICE(USB_VENDOR_ID_REALTEK, 0x8197)}, ++ {USB_DEVICE(USB_VENDOR_ID_REALTEK, 0x8198)}, ++ {} ++}; ++ ++static char* ifname = "wlan%d"; ++#if 0 ++static int hwseqnum = 0; ++static int hwwep = 0; ++#endif ++static int channels = 0x3fff; ++//static int channels = 0x7ff;// change by thomas, use 1 - 11 channel 0907-2007 ++#define eqMacAddr(a,b) ( ((a)[0]==(b)[0] && (a)[1]==(b)[1] && (a)[2]==(b)[2] && (a)[3]==(b)[3] && (a)[4]==(b)[4] && (a)[5]==(b)[5]) ? 1:0 ) ++//by amy for rate adaptive ++#define DEFAULT_RATE_ADAPTIVE_TIMER_PERIOD 300 ++//by amy for rate adaptive ++//by amy for ps ++#define IEEE80211_WATCH_DOG_TIME 2000 ++//by amy for ps ++MODULE_LICENSE("GPL"); ++#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0)) ++MODULE_VERSION("V 1.1"); ++#endif ++MODULE_DEVICE_TABLE(usb, rtl8187_usb_id_tbl); ++MODULE_AUTHOR("Realsil Wlan"); ++MODULE_DESCRIPTION("Linux driver for Realtek RTL8187 WiFi cards"); ++ ++#if 0 ++MODULE_PARM(ifname,"s"); ++MODULE_PARM_DESC(devname," Net interface name, wlan%d=default"); ++ ++MODULE_PARM(hwseqnum,"i"); ++MODULE_PARM_DESC(hwseqnum," Try to use hardware 802.11 header sequence numbers. Zero=default"); ++ ++MODULE_PARM(hwwep,"i"); ++MODULE_PARM_DESC(hwwep," Try to use hardware WEP support. Still broken and not available on all cards"); ++ ++MODULE_PARM(channels,"i"); ++MODULE_PARM_DESC(channels," Channel bitmask for specific locales. NYI"); ++#endif ++ ++#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 9) ++module_param(ifname, charp, S_IRUGO|S_IWUSR ); ++//module_param(hwseqnum,int, S_IRUGO|S_IWUSR); ++//module_param(hwwep,int, S_IRUGO|S_IWUSR); ++module_param(channels,int, S_IRUGO|S_IWUSR); ++#else ++MODULE_PARM(ifname, "s"); ++//MODULE_PARM(hwseqnum,"i"); ++//MODULE_PARM(hwwep,"i"); ++MODULE_PARM(channels,"i"); ++#endif ++ ++MODULE_PARM_DESC(devname," Net interface name, wlan%d=default"); ++//MODULE_PARM_DESC(hwseqnum," Try to use hardware 802.11 header sequence numbers. Zero=default"); ++//MODULE_PARM_DESC(hwwep," Try to use hardware WEP support. Still broken and not available on all cards"); ++MODULE_PARM_DESC(channels," Channel bitmask for specific locales. NYI"); ++ ++#if LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0) ++static int __devinit rtl8187_usb_probe(struct usb_interface *intf, ++ const struct usb_device_id *id); ++static void __devexit rtl8187_usb_disconnect(struct usb_interface *intf); ++#else ++static void *__devinit rtl8187_usb_probe(struct usb_device *udev,unsigned int ifnum, ++ const struct usb_device_id *id); ++static void __devexit rtl8187_usb_disconnect(struct usb_device *udev, void *ptr); ++#endif ++ ++ ++static struct usb_driver rtl8187_usb_driver = { ++#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 15) ++ .owner = THIS_MODULE, ++#endif ++ .name = RTL8187_MODULE_NAME, /* Driver name */ ++ .id_table = rtl8187_usb_id_tbl, /* PCI_ID table */ ++ .probe = rtl8187_usb_probe, /* probe fn */ ++ .disconnect = rtl8187_usb_disconnect, /* remove fn */ ++#if LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0) ++#ifdef CONFIG_RTL8180_PM ++ .suspend = rtl8187_suspend, /* PM suspend fn */ ++ .resume = rtl8187_resume, /* PM resume fn */ ++#else ++ .suspend = NULL, /* PM suspend fn */ ++ .resume = NULL, /* PM resume fn */ ++#endif ++#endif ++}; ++ ++#ifdef JOHN_HWSEC ++void CAM_mark_invalid(struct net_device *dev, u8 ucIndex) ++{ ++ u32 ulContent=0; ++ u32 ulCommand=0; ++ u32 ulEncAlgo=CAM_AES; ++ ++ // keyid must be set in config field ++ ulContent |= (ucIndex&3) | ((u16)(ulEncAlgo)<<2); ++ ++ ulContent |= BIT15; ++ // polling bit, and No Write enable, and address ++ ulCommand= CAM_CONTENT_COUNT*ucIndex; ++ ulCommand= ulCommand | BIT31|BIT16; ++ // write content 0 is equall to mark invalid ++ ++ write_nic_dword(dev, WCAMI, ulContent); //delay_ms(40); ++ //RT_TRACE(COMP_SEC, DBG_LOUD, ("CAM_mark_invalid(): WRITE A4: %x \n",ulContent)); ++ write_nic_dword(dev, RWCAM, ulCommand); //delay_ms(40); ++ //RT_TRACE(COMP_SEC, DBG_LOUD, ("CAM_mark_invalid(): WRITE A0: %x \n",ulCommand)); ++} ++ ++void CAM_empty_entry(struct net_device *dev, u8 ucIndex) ++{ ++ u32 ulCommand=0; ++ u32 ulContent=0; ++ u8 i; ++ u32 ulEncAlgo=CAM_AES; ++ ++ for(i=0;i<6;i++) ++ { ++ ++ // filled id in CAM config 2 byte ++ if( i == 0) ++ { ++ ulContent |=(ucIndex & 0x03) | (ulEncAlgo<<2); ++ ulContent |= BIT15; ++ ++ } ++ else ++ { ++ ulContent = 0; ++ } ++ // polling bit, and No Write enable, and address ++ ulCommand= CAM_CONTENT_COUNT*ucIndex+i; ++ ulCommand= ulCommand | BIT31|BIT16; ++ // write content 0 is equall to mark invalid ++ write_nic_dword(dev, WCAMI, ulContent); //delay_ms(40); ++ //RT_TRACE(COMP_SEC, DBG_LOUD, ("CAM_empty_entry(): WRITE A4: %x \n",ulContent)); ++ write_nic_dword(dev, RWCAM, ulCommand); //delay_ms(40); ++ //RT_TRACE(COMP_SEC, DBG_LOUD, ("CAM_empty_entry(): WRITE A0: %x \n",ulCommand)); ++ } ++} ++ ++void CamResetAllEntry(struct net_device *dev) ++{ ++ u8 ucIndex; ++ ++ //2004/02/11 In static WEP, OID_ADD_KEY or OID_ADD_WEP are set before STA associate to AP. ++ // However, ResetKey is called on OID_802_11_INFRASTRUCTURE_MODE and MlmeAssociateRequest ++ // In this condition, Cam can not be reset because upper layer will not set this static key again. ++ //if(Adapter->EncAlgorithm == WEP_Encryption) ++ // return; ++ //debug ++ //DbgPrint("========================================\n"); ++ //DbgPrint(" Call ResetAllEntry \n"); ++ //DbgPrint("========================================\n\n"); ++ ++ for(ucIndex=0;ucIndex<TOTAL_CAM_ENTRY;ucIndex++) ++ CAM_mark_invalid(dev, ucIndex); ++ for(ucIndex=0;ucIndex<TOTAL_CAM_ENTRY;ucIndex++) ++ CAM_empty_entry(dev, ucIndex); ++ ++} ++ ++ ++void write_cam(struct net_device *dev, u8 addr, u32 data) ++{ ++ write_nic_dword(dev, WCAMI, data); ++ write_nic_dword(dev, RWCAM, BIT31|BIT16|(addr&0xff) ); ++} ++u32 read_cam(struct net_device *dev, u8 addr) ++{ ++ write_nic_dword(dev, RWCAM, 0x80000000|(addr&0xff) ); ++ return read_nic_dword(dev, 0xa8); ++} ++#endif /*JOHN_HWSEC*/ ++ ++#ifdef DEBUG_RW_REGISTER ++//lzm add for write time out test ++void add_into_rw_registers(struct net_device *dev, u32 addr, u32 cont, u8 flag) ++{ ++ struct r8180_priv *priv = (struct r8180_priv *)ieee80211_priv(dev); ++ int reg_index = (priv->write_read_register_index % 200) ; ++ ++ priv->write_read_registers[reg_index].address = 0; ++ priv->write_read_registers[reg_index].content = 0; ++ priv->write_read_registers[reg_index].flag = 0; ++ ++ priv->write_read_registers[reg_index].address = addr; ++ priv->write_read_registers[reg_index].content = cont; ++ priv->write_read_registers[reg_index].flag = flag; ++ ++ priv->write_read_register_index = (priv->write_read_register_index + 1) % 200; ++} ++ ++bool print_once = 0; ++ ++void print_rw_registers(struct net_device *dev) ++{ ++ struct r8180_priv *priv = (struct r8180_priv *)ieee80211_priv(dev); ++ int reg_index = 0; ++ int watchdog = 0; ++ if(print_once == false) ++ { ++ print_once = true; ++ for(reg_index = ((priv->write_read_register_index + 1) % 200); watchdog <= 199; reg_index++) ++ { ++ watchdog++; ++ printk("====>reg_addr:0x%x, reg_cont:0x%x, read_or_write:0x%d\n", ++ priv->write_read_registers[reg_index].address, ++ priv->write_read_registers[reg_index].content, ++ priv->write_read_registers[reg_index].flag); ++ } ++ } ++} ++//lzm add for write time out test ++#endif ++ ++#ifdef CPU_64BIT ++void write_nic_byte_E(struct net_device *dev, int indx, u8 data) ++{ ++ int status; ++ struct r8180_priv *priv = (struct r8180_priv *)ieee80211_priv(dev); ++ struct usb_device *udev = priv->udev; ++ ++ status = usb_control_msg(udev, usb_sndctrlpipe(udev, 0), ++ RTL8187_REQ_SET_REGS, RTL8187_REQT_WRITE, ++ indx|0xfe00, 0, &data, 1, HZ / 2); ++ ++//lzm add for write time out test ++#ifdef DEBUG_RW_REGISTER ++ add_into_rw_registers(dev, indx, data, 2); ++#endif ++ ++ if (status < 0) ++ { ++ printk("write_nic_byte_E TimeOut!addr:%x, status:%x\n", indx, status); ++#ifdef DEBUG_RW_REGISTER ++ print_rw_registers(dev); ++#endif ++ } ++} ++ ++u8 read_nic_byte_E(struct net_device *dev, int indx) ++{ ++ int status; ++ u8 data, *buf; ++ dma_addr_t dma_handle; ++ struct r8180_priv *priv = (struct r8180_priv *)ieee80211_priv(dev); ++ struct usb_device *udev = priv->udev; ++ ++ buf = dma_pool_alloc(priv->usb_pool, GFP_ATOMIC, &dma_handle); ++ if (!buf) { ++ printk("read_nic_byte_E out of memory\n"); ++ return -ENOMEM; ++ } ++ status = usb_control_msg(udev, usb_rcvctrlpipe(udev, 0), ++ RTL8187_REQ_GET_REGS, RTL8187_REQT_READ, ++ indx|0xfe00, 0, buf, 1, HZ / 2); ++//lzm add for write time out test ++#ifdef DEBUG_RW_REGISTER ++ add_into_rw_registers(dev, indx, buf[0], 1); ++#endif ++ ++ if (status < 0) ++ { ++ printk("read_nic_byte_E TimeOut!addr:%x, status:%x\n",indx, status); ++#ifdef DEBUG_RW_REGISTER ++ print_rw_registers(dev); ++#endif ++ } ++ ++ data = buf[0]; ++ dma_pool_free(priv->usb_pool, buf, dma_handle); ++ return data; ++} ++ ++void write_nic_byte(struct net_device *dev, int indx, u8 data) ++{ ++ int status; ++ ++ struct r8180_priv *priv = (struct r8180_priv *)ieee80211_priv(dev); ++ struct usb_device *udev = priv->udev; ++ ++ status = usb_control_msg(udev, usb_sndctrlpipe(udev, 0), ++ RTL8187_REQ_SET_REGS, RTL8187_REQT_WRITE, ++ (indx&0xff)|0xff00, (indx>>8)&0x03, &data, 1, HZ / 2); ++ ++//lzm add for write time out test ++#ifdef DEBUG_RW_REGISTER ++ add_into_rw_registers(dev, indx, data, 2); ++#endif ++ if (status < 0) ++ { ++ printk("write_nic_byte TimeOut!addr:%x, status:%x\n",indx, status); ++#ifdef DEBUG_RW_REGISTER ++ print_rw_registers(dev); ++#endif ++ } ++ ++ ++} ++ ++void write_nic_word(struct net_device *dev, int indx, u16 data) ++{ ++ ++ int status; ++ ++ struct r8180_priv *priv = (struct r8180_priv *)ieee80211_priv(dev); ++ struct usb_device *udev = priv->udev; ++ ++ status = usb_control_msg(udev, usb_sndctrlpipe(udev, 0), ++ RTL8187_REQ_SET_REGS, RTL8187_REQT_WRITE, ++ (indx&0xff)|0xff00, (indx>>8)&0x03, &data, 2, HZ / 2); ++ ++//lzm add for write time out test ++#ifdef DEBUG_RW_REGISTER ++ add_into_rw_registers(dev, indx, data, 2); ++ ++ if(priv->write_read_register_index == 199) ++ { ++ //print_rw_registers(dev); ++ } ++#endif ++ if (status < 0) ++ { ++ printk("write_nic_word TimeOut!addr:%x, status:%x\n",indx, status); ++#ifdef DEBUG_RW_REGISTER ++ print_rw_registers(dev); ++#endif ++ } ++ ++} ++ ++void write_nic_dword(struct net_device *dev, int indx, u32 data) ++{ ++ ++ int status; ++ ++ struct r8180_priv *priv = (struct r8180_priv *)ieee80211_priv(dev); ++ struct usb_device *udev = priv->udev; ++ ++ status = usb_control_msg(udev, usb_sndctrlpipe(udev, 0), ++ RTL8187_REQ_SET_REGS, RTL8187_REQT_WRITE, ++ (indx&0xff)|0xff00, (indx>>8)&0x03, &data, 4, HZ / 2); ++//lzm add for write time out test ++#ifdef DEBUG_RW_REGISTER ++ add_into_rw_registers(dev, indx, data, 2); ++#endif ++ ++ ++ if (status < 0) ++ { ++ printk("write_nic_dword TimeOut!addr:%x, status:%x\n",indx, status); ++#ifdef DEBUG_RW_REGISTER ++ print_rw_registers(dev); ++#endif ++ } ++ ++} ++ ++ u8 read_nic_byte(struct net_device *dev, int indx) ++{ ++ u8 data, *buf; ++ int status; ++ struct r8180_priv *priv = (struct r8180_priv *)ieee80211_priv(dev); ++ struct usb_device *udev = priv->udev; ++ dma_addr_t dma_handle; ++ ++ buf = dma_pool_alloc(priv->usb_pool, GFP_ATOMIC, &dma_handle); ++ if (!buf) { ++ printk("read_nic_byte: out of memory\n"); ++ return -ENOMEM; ++ } ++ status = usb_control_msg(udev, usb_rcvctrlpipe(udev, 0), ++ RTL8187_REQ_GET_REGS, RTL8187_REQT_READ, ++ (indx&0xff)|0xff00, (indx>>8)&0x03, buf, 1, HZ / 2); ++//lzm add for write time out test ++#ifdef DEBUG_RW_REGISTER ++ add_into_rw_registers(dev, indx, buf[0], 1); ++#endif ++ ++ if (status < 0) ++ { ++ printk("read_nic_byte TimeOut!addr:%x, status:%x\n",indx, status); ++#ifdef DEBUG_RW_REGISTER ++ print_rw_registers(dev); ++#endif ++ } ++ ++ data = buf[0]; ++ dma_pool_free(priv->usb_pool, buf, dma_handle); ++ return data; ++} ++ ++u16 read_nic_word(struct net_device *dev, int indx) ++{ ++ u16 data, *buf; ++ int status; ++ struct r8180_priv *priv = (struct r8180_priv *)ieee80211_priv(dev); ++ struct usb_device *udev = priv->udev; ++ dma_addr_t dma_handle; ++ ++ buf = dma_pool_alloc(priv->usb_pool, GFP_ATOMIC, &dma_handle); ++ if (!buf) { ++ printk("read_nic_word: out of memory\n"); ++ return -ENOMEM; ++ } ++ status = usb_control_msg(udev, usb_rcvctrlpipe(udev, 0), ++ RTL8187_REQ_GET_REGS, RTL8187_REQT_READ, ++ (indx&0xff)|0xff00, (indx>>8)&0x03, buf, 2, HZ / 2); ++//lzm add for write time out test ++#ifdef DEBUG_RW_REGISTER ++ add_into_rw_registers(dev, indx, buf[0], 1); ++#endif ++ ++ if (status < 0) ++ { ++ printk("read_nic_word TimeOut!addr:%x, status:%x\n",indx, status); ++#ifdef DEBUG_RW_REGISTER ++ print_rw_registers(dev); ++#endif ++ } ++ ++ ++ data = buf[0]; ++ dma_pool_free(priv->usb_pool, buf, dma_handle); ++ return data; ++} ++ ++u32 read_nic_dword(struct net_device *dev, int indx) ++{ ++ u32 data, *buf; ++ int status; ++ dma_addr_t dma_handle; ++// int result; ++ ++ struct r8180_priv *priv = (struct r8180_priv *)ieee80211_priv(dev); ++ struct usb_device *udev = priv->udev; ++ ++ buf = dma_pool_alloc(priv->usb_pool, GFP_ATOMIC, &dma_handle); ++ if (!buf){ ++ printk("read_nic_dword: out of memory\n"); ++ return -ENOMEM; ++ } ++ status = usb_control_msg(udev, usb_rcvctrlpipe(udev, 0), ++ RTL8187_REQ_GET_REGS, RTL8187_REQT_READ, ++ (indx&0xff)|0xff00, (indx>>8)&0x03, buf, 4, HZ / 2); ++//lzm add for write time out test ++#ifdef DEBUG_RW_REGISTER ++ add_into_rw_registers(dev, indx, buf[0], 1); ++#endif ++ ++ if (status < 0) ++ { ++ printk("read_nic_dword TimeOut!addr:%x, status:%x\n",indx, status); ++#ifdef DEBUG_RW_REGISTER ++ print_rw_registers(dev); ++#endif ++ } ++ ++ ++ ++ data = buf[0]; ++ dma_pool_free(priv->usb_pool, buf, dma_handle); ++ return data; ++} ++#else ++void write_nic_byte_E(struct net_device *dev, int indx, u8 data) ++{ ++ int status; ++ struct r8180_priv *priv = (struct r8180_priv *)ieee80211_priv(dev); ++ struct usb_device *udev = priv->udev; ++ ++ status = usb_control_msg(udev, usb_sndctrlpipe(udev, 0), ++ RTL8187_REQ_SET_REGS, RTL8187_REQT_WRITE, ++ indx|0xfe00, 0, &data, 1, HZ / 2); ++ ++ if (status < 0) ++ { ++ printk("write_nic_byte_E TimeOut!addr:0x%x,val:0x%x, status:%x\n", indx,data,status); ++ } ++} ++ ++u8 read_nic_byte_E(struct net_device *dev, int indx) ++{ ++ int status; ++ u8 data = 0; ++ u8 buf[64]; ++ struct r8180_priv *priv = (struct r8180_priv *)ieee80211_priv(dev); ++ struct usb_device *udev = priv->udev; ++ ++ status = usb_control_msg(udev, usb_rcvctrlpipe(udev, 0), ++ RTL8187_REQ_GET_REGS, RTL8187_REQT_READ, ++ indx|0xfe00, 0, buf, 1, HZ / 2); ++ ++ if (status < 0) ++ { ++ printk("read_nic_byte_E TimeOut!addr:0x%x, status:%x\n", indx, status); ++ } ++ ++ data = *(u8*)buf; ++ return data; ++} ++ ++void write_nic_byte(struct net_device *dev, int indx, u8 data) ++{ ++ int status; ++ ++ struct r8180_priv *priv = (struct r8180_priv *)ieee80211_priv(dev); ++ struct usb_device *udev = priv->udev; ++ ++ status = usb_control_msg(udev, usb_sndctrlpipe(udev, 0), ++ RTL8187_REQ_SET_REGS, RTL8187_REQT_WRITE, ++ (indx&0xff)|0xff00, (indx>>8)&0x03, &data, 1, HZ / 2); ++ ++ if (status < 0) ++ { ++ printk("write_nic_byte TimeOut!addr:0x%x,val:0x%x, status:%x\n", indx,data, status); ++ } ++ ++ ++} ++ ++void write_nic_word(struct net_device *dev, int indx, u16 data) ++{ ++ ++ int status; ++ ++ struct r8180_priv *priv = (struct r8180_priv *)ieee80211_priv(dev); ++ struct usb_device *udev = priv->udev; ++ ++ status = usb_control_msg(udev, usb_sndctrlpipe(udev, 0), ++ RTL8187_REQ_SET_REGS, RTL8187_REQT_WRITE, ++ (indx&0xff)|0xff00, (indx>>8)&0x03, &data, 2, HZ / 2); ++ ++ if (status < 0) ++ { ++ printk("write_nic_word TimeOut!addr:0x%x,val:0x%x, status:%x\n", indx,data, status); ++ } ++ ++} ++ ++void write_nic_dword(struct net_device *dev, int indx, u32 data) ++{ ++ ++ int status; ++ ++ struct r8180_priv *priv = (struct r8180_priv *)ieee80211_priv(dev); ++ struct usb_device *udev = priv->udev; ++ ++ status = usb_control_msg(udev, usb_sndctrlpipe(udev, 0), ++ RTL8187_REQ_SET_REGS, RTL8187_REQT_WRITE, ++ (indx&0xff)|0xff00, (indx>>8)&0x03, &data, 4, HZ / 2); ++ ++ ++ if (status < 0) ++ { ++ printk("write_nic_dword TimeOut!addr:0x%x,val:0x%x, status:%x\n", indx,data, status); ++ } ++ ++} ++ ++u8 read_nic_byte(struct net_device *dev, int indx) ++{ ++ u8 data = 0; ++ u8 buf[64]; ++ int status; ++ struct r8180_priv *priv = (struct r8180_priv *)ieee80211_priv(dev); ++ struct usb_device *udev = priv->udev; ++ ++ status = usb_control_msg(udev, usb_rcvctrlpipe(udev, 0), ++ RTL8187_REQ_GET_REGS, RTL8187_REQT_READ, ++ (indx&0xff)|0xff00, (indx>>8)&0x03, buf, 1, HZ / 2); ++ ++ if (status < 0) ++ { ++ printk("read_nic_byte TimeOut!addr:0x%x,status:%x\n", indx,status); ++ } ++ ++ ++ data = *(u8*)buf; ++ return data; ++} ++ ++u16 read_nic_word(struct net_device *dev, int indx) ++{ ++ u16 data = 0; ++ u8 buf[64]; ++ int status; ++ struct r8180_priv *priv = (struct r8180_priv *)ieee80211_priv(dev); ++ struct usb_device *udev = priv->udev; ++ ++ status = usb_control_msg(udev, usb_rcvctrlpipe(udev, 0), ++ RTL8187_REQ_GET_REGS, RTL8187_REQT_READ, ++ (indx&0xff)|0xff00, (indx>>8)&0x03, buf, 2, HZ / 2); ++ ++ if (status < 0) ++ { ++ printk("read_nic_word TimeOut!addr:0x%x,status:%x\n", indx,status); ++ } ++ ++ data = *(u16*)buf; ++ return data; ++} ++ ++u32 read_nic_dword(struct net_device *dev, int indx) ++{ ++ u32 data = 0; ++ u8 buf[64]; ++ int status; ++ ++ struct r8180_priv *priv = (struct r8180_priv *)ieee80211_priv(dev); ++ struct usb_device *udev = priv->udev; ++ ++ status = usb_control_msg(udev, usb_rcvctrlpipe(udev, 0), ++ RTL8187_REQ_GET_REGS, RTL8187_REQT_READ, ++ (indx&0xff)|0xff00, (indx>>8)&0x03, buf, 4, HZ / 2); ++ ++ if (status < 0) ++ { ++ printk("read_nic_dword TimeOut!addr:0x%x,status:%x\n", indx, status); ++ } ++ ++ ++ data = *(u32*)buf; ++ return data; ++} ++#endif ++ ++ ++u8 read_phy_cck(struct net_device *dev, u8 adr); ++u8 read_phy_ofdm(struct net_device *dev, u8 adr); ++/* this might still called in what was the PHY rtl8185/rtl8187 common code ++ * plans are to possibilty turn it again in one common code... ++ */ ++inline void force_pci_posting(struct net_device *dev) ++{ ++} ++ ++ ++static struct net_device_stats *rtl8180_stats(struct net_device *dev); ++void rtl8180_commit(struct net_device *dev); ++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,20)) ++void rtl8180_restart(struct work_struct *work); ++#else ++void rtl8180_restart(struct net_device *dev); ++#endif ++/**************************************************************************** ++ -----------------------------PROCFS STUFF------------------------- ++*****************************************************************************/ ++ ++static struct proc_dir_entry *rtl8180_proc = NULL; ++static int proc_get_stats_ap(char *page, char **start, ++ off_t offset, int count, ++ int *eof, void *data) ++{ ++ struct net_device *dev = data; ++ struct r8180_priv *priv = (struct r8180_priv *)ieee80211_priv(dev); ++ struct ieee80211_device *ieee = priv->ieee80211; ++ struct ieee80211_network *target; ++ ++ int len = 0; ++ ++ list_for_each_entry(target, &ieee->network_list, list) { ++ ++ len += snprintf(page + len, count - len, ++ "%s ", target->ssid); ++ len += snprintf(page + len, count - len, ++ "%ld ", (jiffies-target->last_scanned)/HZ); ++ ++ ++ ++ if(target->wpa_ie_len>0 || target->rsn_ie_len>0){ ++ len += snprintf(page + len, count - len, ++ "WPA\n"); ++ } ++ else{ ++ len += snprintf(page + len, count - len, ++ "non_WPA\n"); ++ } ++ ++ } ++ ++ *eof = 1; ++ return len; ++} ++ ++static int proc_get_registers(char *page, char **start, ++ off_t offset, int count, ++ int *eof, void *data) ++{ ++ struct net_device *dev = data; ++ ++ int len = 0; ++ int i,n; ++ ++ int max=0xff; ++ ++ /* This dump the current register page */ ++len += snprintf(page + len, count - len, ++ "\n####################page 0##################\n "); ++ ++ for(n=0;n<=max;) ++ { ++ //printk( "\nD: %2x> ", n); ++ len += snprintf(page + len, count - len, ++ "\nD: %2x > ",n); ++ ++ for(i=0;i<16 && n<=max;i++,n++) ++ len += snprintf(page + len, count - len, ++ "%2x ",read_nic_byte(dev,n)); ++ ++ // printk("%2x ",read_nic_byte(dev,n)); ++ } ++ len += snprintf(page + len, count - len,"\n"); ++len += snprintf(page + len, count - len, ++ "\n####################page 1##################\n "); ++ for(n=0;n<=max;) ++ { ++ //printk( "\nD: %2x> ", n); ++ len += snprintf(page + len, count - len, ++ "\nD: %2x > ",n); ++ ++ for(i=0;i<16 && n<=max;i++,n++) ++ len += snprintf(page + len, count - len, ++ "%2x ",read_nic_byte(dev,0x100|n)); ++ ++ // printk("%2x ",read_nic_byte(dev,n)); ++ } ++len += snprintf(page + len, count - len, ++ "\n####################page 2##################\n "); ++ for(n=0;n<=max;) ++ { ++ //printk( "\nD: %2x> ", n); ++ len += snprintf(page + len, count - len, ++ "\nD: %2x > ",n); ++ ++ for(i=0;i<16 && n<=max;i++,n++) ++ len += snprintf(page + len, count - len, ++ "%2x ",read_nic_byte(dev,0x200|n)); ++ ++ // printk("%2x ",read_nic_byte(dev,n)); ++ } ++ ++ ++ ++ *eof = 1; ++ return len; ++ ++} ++ ++ ++static int proc_get_cck_reg(char *page, char **start, ++ off_t offset, int count, ++ int *eof, void *data) ++{ ++ struct net_device *dev = data; ++ ++ int len = 0; ++ int i,n; ++ ++ int max = 0x5F; ++ ++ /* This dump the current register page */ ++ for(n=0;n<=max;) ++ { ++ //printk( "\nD: %2x> ", n); ++ len += snprintf(page + len, count - len, ++ "\nD: %2x > ",n); ++ ++ for(i=0;i<16 && n<=max;i++,n++) ++ len += snprintf(page + len, count - len, ++ "%2x ",read_phy_cck(dev,n)); ++ ++ // printk("%2x ",read_nic_byte(dev,n)); ++ } ++ len += snprintf(page + len, count - len,"\n"); ++ ++ ++ *eof = 1; ++ return len; ++ ++} ++ ++ ++static int proc_get_ofdm_reg(char *page, char **start, ++ off_t offset, int count, ++ int *eof, void *data) ++{ ++ struct net_device *dev = data; ++ ++ int len = 0; ++ int i,n; ++ ++ //int max=0xff; ++ int max = 0x40; ++ ++ /* This dump the current register page */ ++ for(n=0;n<=max;) ++ { ++ //printk( "\nD: %2x> ", n); ++ len += snprintf(page + len, count - len, ++ "\nD: %2x > ",n); ++ ++ for(i=0;i<16 && n<=max;i++,n++) ++ len += snprintf(page + len, count - len, ++ "%2x ",read_phy_ofdm(dev,n)); ++ ++ // printk("%2x ",read_nic_byte(dev,n)); ++ } ++ len += snprintf(page + len, count - len,"\n"); ++ ++ ++ ++ *eof = 1; ++ return len; ++ ++} ++ ++ ++#if 0 ++static int proc_get_stats_hw(char *page, char **start, ++ off_t offset, int count, ++ int *eof, void *data) ++{ ++ struct net_device *dev = data; ++ struct r8180_priv *priv = (struct r8180_priv *)ieee80211_priv(dev); ++ ++ int len = 0; ++ ++ len += snprintf(page + len, count - len, ++ "NIC int: %lu\n" ++ "Total int: %lu\n", ++ priv->stats.ints, ++ priv->stats.shints); ++ ++ *eof = 1; ++ return len; ++} ++#endif ++ ++static int proc_get_stats_tx(char *page, char **start, ++ off_t offset, int count, ++ int *eof, void *data) ++{ ++ struct net_device *dev = data; ++ struct r8180_priv *priv = (struct r8180_priv *)ieee80211_priv(dev); ++ ++ int len = 0; ++ ++ len += snprintf(page + len, count - len, ++ "TX VI priority ok int: %lu\n" ++ "TX VI priority error int: %lu\n" ++ "TX VO priority ok int: %lu\n" ++ "TX VO priority error int: %lu\n" ++ "TX BE priority ok int: %lu\n" ++ "TX BE priority error int: %lu\n" ++ "TX BK priority ok int: %lu\n" ++ "TX BK priority error int: %lu\n" ++ "TX MANAGE priority ok int: %lu\n" ++ "TX MANAGE priority error int: %lu\n" ++ "TX BEACON priority ok int: %lu\n" ++ "TX BEACON priority error int: %lu\n" ++// "TX high priority ok int: %lu\n" ++// "TX high priority failed error int: %lu\n" ++ "TX queue resume: %lu\n" ++ "TX queue stopped?: %d\n" ++ "TX fifo overflow: %lu\n" ++// "TX beacon: %lu\n" ++ "TX VI queue: %d\n" ++ "TX VO queue: %d\n" ++ "TX BE queue: %d\n" ++ "TX BK queue: %d\n" ++ "TX BEACON queue: %d\n" ++ "TX MANAGE queue: %d\n" ++// "TX HW queue: %d\n" ++ "TX VI dropped: %lu\n" ++ "TX VO dropped: %lu\n" ++ "TX BE dropped: %lu\n" ++ "TX BK dropped: %lu\n" ++ "TX total data packets %lu\n", ++// "TX beacon aborted: %lu\n", ++ priv->stats.txviokint, ++ priv->stats.txvierr, ++ priv->stats.txvookint, ++ priv->stats.txvoerr, ++ priv->stats.txbeokint, ++ priv->stats.txbeerr, ++ priv->stats.txbkokint, ++ priv->stats.txbkerr, ++ priv->stats.txmanageokint, ++ priv->stats.txmanageerr, ++ priv->stats.txbeaconokint, ++ priv->stats.txbeaconerr, ++// priv->stats.txhpokint, ++// priv->stats.txhperr, ++ priv->stats.txresumed, ++ netif_queue_stopped(dev), ++ priv->stats.txoverflow, ++// priv->stats.txbeacon, ++ atomic_read(&(priv->tx_pending[VI_PRIORITY])), ++ atomic_read(&(priv->tx_pending[VO_PRIORITY])), ++ atomic_read(&(priv->tx_pending[BE_PRIORITY])), ++ atomic_read(&(priv->tx_pending[BK_PRIORITY])), ++ atomic_read(&(priv->tx_pending[BEACON_PRIORITY])), ++ atomic_read(&(priv->tx_pending[MANAGE_PRIORITY])), ++// read_nic_byte(dev, TXFIFOCOUNT), ++ priv->stats.txvidrop, ++ priv->stats.txvodrop, ++ priv->stats.txbedrop, ++ priv->stats.txbkdrop, ++ priv->stats.txdatapkt ++// priv->stats.txbeaconerr ++ ); ++ ++ *eof = 1; ++ return len; ++} ++ ++ ++ ++static int proc_get_stats_rx(char *page, char **start, ++ off_t offset, int count, ++ int *eof, void *data) ++{ ++ struct net_device *dev = data; ++ struct r8180_priv *priv = (struct r8180_priv *)ieee80211_priv(dev); ++ ++ int len = 0; ++ ++ len += snprintf(page + len, count - len, ++ "RX packets: %lu\n" ++ "RX urb status error: %lu\n" ++ "RX invalid urb error: %lu\n", ++ priv->stats.rxok, ++ priv->stats.rxstaterr, ++ priv->stats.rxurberr); ++ ++ *eof = 1; ++ return len; ++} ++ ++#if WIRELESS_EXT < 17 ++static struct iw_statistics *r8180_get_wireless_stats(struct net_device *dev) ++{ ++ struct r8180_priv *priv = ieee80211_priv(dev); ++ ++ return &priv->wstats; ++} ++#endif ++ ++void rtl8180_proc_module_init(void) ++{ ++ DMESG("Initializing proc filesystem"); ++#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,24)) ++ rtl8180_proc=create_proc_entry(RTL8187_MODULE_NAME, S_IFDIR, proc_net); ++#else ++ rtl8180_proc=create_proc_entry(RTL8187_MODULE_NAME, S_IFDIR, init_net.proc_net); ++#endif ++} ++ ++ ++void rtl8180_proc_module_remove(void) ++{ ++#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,24)) ++ remove_proc_entry(RTL8187_MODULE_NAME, proc_net); ++#else ++ remove_proc_entry(RTL8187_MODULE_NAME, init_net.proc_net); ++#endif ++} ++ ++ ++void rtl8180_proc_remove_one(struct net_device *dev) ++{ ++ struct r8180_priv *priv = (struct r8180_priv *)ieee80211_priv(dev); ++ if (priv->dir_dev) { ++ // remove_proc_entry("stats-hw", priv->dir_dev); ++ remove_proc_entry("stats-tx", priv->dir_dev); ++ remove_proc_entry("stats-rx", priv->dir_dev); ++ // remove_proc_entry("stats-ieee", priv->dir_dev); ++ remove_proc_entry("stats-ap", priv->dir_dev); ++ remove_proc_entry("registers", priv->dir_dev); ++ remove_proc_entry("cck-registers",priv->dir_dev); ++ remove_proc_entry("ofdm-registers",priv->dir_dev); ++ remove_proc_entry(dev->name, rtl8180_proc); ++ priv->dir_dev = NULL; ++ } ++} ++ ++ ++void rtl8180_proc_init_one(struct net_device *dev) ++{ ++ struct proc_dir_entry *e; ++ struct r8180_priv *priv = (struct r8180_priv *)ieee80211_priv(dev); ++ priv->dir_dev = create_proc_entry(dev->name, ++ S_IFDIR | S_IRUGO | S_IXUGO, ++ rtl8180_proc); ++ if (!priv->dir_dev) { ++ DMESGE("Unable to initialize /proc/net/rtl8187/%s\n", ++ dev->name); ++ return; ++ } ++ #if 0 ++ e = create_proc_read_entry("stats-hw", S_IFREG | S_IRUGO, ++ priv->dir_dev, proc_get_stats_hw, dev); ++ ++ if (!e) { ++ DMESGE("Unable to initialize " ++ "/proc/net/rtl8187/%s/stats-hw\n", ++ dev->name); ++ } ++ #endif ++ e = create_proc_read_entry("stats-rx", S_IFREG | S_IRUGO, ++ priv->dir_dev, proc_get_stats_rx, dev); ++ ++ if (!e) { ++ DMESGE("Unable to initialize " ++ "/proc/net/rtl8187/%s/stats-rx\n", ++ dev->name); ++ } ++ ++ ++ e = create_proc_read_entry("stats-tx", S_IFREG | S_IRUGO, ++ priv->dir_dev, proc_get_stats_tx, dev); ++ ++ if (!e) { ++ DMESGE("Unable to initialize " ++ "/proc/net/rtl8187/%s/stats-tx\n", ++ dev->name); ++ } ++ #if 0 ++ e = create_proc_read_entry("stats-ieee", S_IFREG | S_IRUGO, ++ priv->dir_dev, proc_get_stats_ieee, dev); ++ ++ if (!e) { ++ DMESGE("Unable to initialize " ++ "/proc/net/rtl8187/%s/stats-ieee\n", ++ dev->name); ++ } ++ ++ #endif ++ ++ e = create_proc_read_entry("stats-ap", S_IFREG | S_IRUGO, ++ priv->dir_dev, proc_get_stats_ap, dev); ++ ++ if (!e) { ++ DMESGE("Unable to initialize " ++ "/proc/net/rtl8187/%s/stats-ap\n", ++ dev->name); ++ } ++ ++ e = create_proc_read_entry("registers", S_IFREG | S_IRUGO, ++ priv->dir_dev, proc_get_registers, dev); ++ if (!e) { ++ DMESGE("Unable to initialize " ++ "/proc/net/rtl8187/%s/registers\n", ++ dev->name); ++ } ++ ++ e = create_proc_read_entry("cck-registers", S_IFREG | S_IRUGO, ++ priv->dir_dev, proc_get_cck_reg, dev); ++ if (!e) { ++ DMESGE("Unable to initialize " ++ "/proc/net/rtl8187/%s/cck-registers\n", ++ dev->name); ++ } ++ ++ e = create_proc_read_entry("ofdm-registers", S_IFREG | S_IRUGO, ++ priv->dir_dev, proc_get_ofdm_reg, dev); ++ if (!e) { ++ DMESGE("Unable to initialize " ++ "/proc/net/rtl8187/%s/ofdm-registers\n", ++ dev->name); ++ } ++ ++#ifdef _RTL8187_EXT_PATCH_ ++ if( priv->mshobj && priv->mshobj->ext_patch_create_proc ) ++ priv->mshobj->ext_patch_create_proc(priv); ++#endif ++ ++} ++/**************************************************************************** ++ -----------------------------MISC STUFF------------------------- ++*****************************************************************************/ ++ ++/* this is only for debugging */ ++void print_buffer(u32 *buffer, int len) ++{ ++ int i; ++ u8 *buf =(u8*)buffer; ++ ++ printk("ASCII BUFFER DUMP (len: %x):\n",len); ++ ++ for(i=0;i<len;i++) ++ printk("%c",buf[i]); ++ ++ printk("\nBINARY BUFFER DUMP (len: %x):\n",len); ++ ++ for(i=0;i<len;i++) ++ printk("%x",buf[i]); ++ ++ printk("\n"); ++} ++ ++short check_nic_enought_desc(struct net_device *dev, priority_t priority) ++{ ++ struct r8180_priv *priv = ieee80211_priv(dev); ++ //int used = atomic_read((priority == NORM_PRIORITY) ? ++ // &priv->tx_np_pending : &priv->tx_lp_pending); ++ int used = atomic_read(&priv->tx_pending[priority]); ++ ++ return (used < MAX_TX_URB); ++} ++ ++void tx_timeout(struct net_device *dev) ++{ ++ struct r8180_priv *priv = ieee80211_priv(dev); ++ //rtl8180_commit(dev); ++ printk("@@@@ Transmit timeout at %ld, latency %ld\n", jiffies, ++ jiffies - dev->trans_start); ++ ++ printk("@@@@ netif_queue_stopped = %d\n", netif_queue_stopped(dev)); ++ ++#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0)) ++ schedule_work(&priv->reset_wq); ++#else ++ schedule_task(&priv->reset_wq); ++#endif ++ //DMESG("TXTIMEOUT"); ++} ++ ++ ++/* this is only for debug */ ++void dump_eprom(struct net_device *dev) ++{ ++ int i; ++ for(i=0; i<63; i++) ++ DMESG("EEPROM addr %x : %x", i, eprom_read(dev,i)); ++} ++ ++/* this is only for debug */ ++void rtl8180_dump_reg(struct net_device *dev) ++{ ++ int i; ++ int n; ++ int max=0xff; ++ ++ DMESG("Dumping NIC register map"); ++ ++ for(n=0;n<=max;) ++ { ++ printk( "\nD: %2x> ", n); ++ for(i=0;i<16 && n<=max;i++,n++) ++ printk("%2x ",read_nic_byte(dev,n)); ++ } ++ printk("\n"); ++} ++ ++/**************************************************************************** ++ ------------------------------HW STUFF--------------------------- ++*****************************************************************************/ ++ ++ ++void rtl8180_irq_enable(struct net_device *dev) ++{ ++ struct r8180_priv *priv = (struct r8180_priv *)ieee80211_priv(dev); ++ //priv->irq_enabled = 1; ++ ++ //write_nic_word(dev,INTA_MASK,INTA_RXOK | INTA_RXDESCERR | INTA_RXOVERFLOW | ++ // INTA_TXOVERFLOW | INTA_HIPRIORITYDESCERR | INTA_HIPRIORITYDESCOK | ++ // INTA_NORMPRIORITYDESCERR | INTA_NORMPRIORITYDESCOK | ++ // INTA_LOWPRIORITYDESCERR | INTA_LOWPRIORITYDESCOK | INTA_TIMEOUT); ++ ++ write_nic_word(dev,INTA_MASK, priv->irq_mask); ++} ++ ++ ++void rtl8180_irq_disable(struct net_device *dev) ++{ ++ write_nic_word(dev,INTA_MASK,0); ++ force_pci_posting(dev); ++// priv->irq_enabled = 0; ++} ++ ++ ++void rtl8180_set_mode(struct net_device *dev,int mode) ++{ ++ u8 ecmd; ++ ecmd=read_nic_byte(dev, EPROM_CMD); ++ ecmd=ecmd &~ EPROM_CMD_OPERATING_MODE_MASK; ++ ecmd=ecmd | (mode<<EPROM_CMD_OPERATING_MODE_SHIFT); ++ ecmd=ecmd &~ (1<<EPROM_CS_SHIFT); ++ ecmd=ecmd &~ (1<<EPROM_CK_SHIFT); ++ write_nic_byte(dev, EPROM_CMD, ecmd); ++} ++ ++ ++void rtl8180_update_msr(struct net_device *dev) ++{ ++ struct r8180_priv *priv = ieee80211_priv(dev); ++ u8 msr; ++ ++ msr = read_nic_byte(dev, MSR); ++ msr &= ~ MSR_LINK_MASK; ++ ++ /* do not change in link_state != WLAN_LINK_ASSOCIATED. ++ * msr must be updated if the state is ASSOCIATING. ++ * this is intentional and make sense for ad-hoc and ++ * master (see the create BSS/IBSS func) ++ */ ++ if (priv->ieee80211->state == IEEE80211_LINKED){ ++ ++ if (priv->ieee80211->iw_mode == IW_MODE_INFRA) ++ msr |= (MSR_LINK_MANAGED<<MSR_LINK_SHIFT); ++ else if (priv->ieee80211->iw_mode == IW_MODE_ADHOC) ++ msr |= (MSR_LINK_ADHOC<<MSR_LINK_SHIFT); ++ else if (priv->ieee80211->iw_mode == IW_MODE_MASTER) ++ msr |= (MSR_LINK_MASTER<<MSR_LINK_SHIFT); ++ ++ }else ++ msr |= (MSR_LINK_NONE<<MSR_LINK_SHIFT); ++ ++ write_nic_byte(dev, MSR, msr); ++} ++ ++void rtl8180_set_chan(struct net_device *dev,short ch) ++{ ++ struct r8180_priv *priv = (struct r8180_priv *)ieee80211_priv(dev); ++ u32 tx; ++ ++ priv->chan=ch; ++ #if 0 ++ if(priv->ieee80211->iw_mode == IW_MODE_ADHOC || ++ priv->ieee80211->iw_mode == IW_MODE_MASTER){ ++ ++ priv->ieee80211->link_state = WLAN_LINK_ASSOCIATED; ++ priv->ieee80211->master_chan = ch; ++ rtl8180_update_beacon_ch(dev); ++ } ++ #endif ++ ++ /* this hack should avoid frame TX during channel setting*/ ++ tx = read_nic_dword(dev,TX_CONF); ++ tx &= ~TX_LOOPBACK_MASK; ++ ++#ifndef LOOP_TEST ++ write_nic_dword(dev,TX_CONF, tx |( TX_LOOPBACK_MAC<<TX_LOOPBACK_SHIFT)); ++ priv->rf_set_chan(dev,priv->chan); ++ //mdelay(10); //CPU occupany is too high. LZM 31/10/2008 ++ write_nic_dword(dev,TX_CONF,tx | (TX_LOOPBACK_NONE<<TX_LOOPBACK_SHIFT)); ++#endif ++} ++ ++#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,20) ++void rtl8187_rx_isr(struct urb *rx_urb, struct pt_regs *regs); ++#else ++void rtl8187_rx_isr(struct urb* rx_urb); ++#endif ++#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,20) ++void rtl8187_rx_manage_isr(struct urb *rx_urb, struct pt_regs *regs); ++#else ++void rtl8187_rx_manage_isr(struct urb* rx_urb); ++#endif ++ ++ ++ ++void rtl8187_rx_urbsubmit(struct net_device *dev, struct urb* rx_urb) ++{ ++ struct r8180_priv *priv = (struct r8180_priv *)ieee80211_priv(dev); ++ int err; ++ ++ usb_fill_bulk_urb(rx_urb,priv->udev, ++ usb_rcvbulkpipe(priv->udev,(NIC_8187 == priv->card_8187)?0x81:0x83), ++ rx_urb->transfer_buffer, ++ RX_URB_SIZE, ++ rtl8187_rx_isr, ++ dev); ++#if LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0) ++ err = usb_submit_urb(rx_urb, GFP_ATOMIC); ++#else ++ err = usb_submit_urb(rx_urb); ++#endif ++ if(err && err != -EPERM){ ++ DMESGE("cannot submit RX command. URB_STATUS %x",rx_urb->status); ++ } ++} ++ ++ ++void rtl8187_rx_manage_urbsubmit(struct net_device *dev, struct urb* rx_urb) ++{ ++ struct r8180_priv *priv = (struct r8180_priv *)ieee80211_priv(dev); ++ int err; ++#ifdef THOMAS_BEACON ++ usb_fill_bulk_urb(rx_urb,priv->udev, ++ usb_rcvbulkpipe(priv->udev,0x09), ++ rx_urb->transfer_buffer, ++ rx_urb->transfer_buffer_length, ++ rtl8187_rx_manage_isr, dev); ++#endif ++ ++#if LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0) ++ err = usb_submit_urb(rx_urb, GFP_ATOMIC); ++#else ++ err = usb_submit_urb(rx_urb); ++#endif ++ if(err && err != -EPERM){ ++ DMESGE("cannot submit RX command. URB_STATUS %x",rx_urb->status); ++ } ++} ++ ++ ++ ++void rtl8187_rx_initiate(struct net_device *dev) ++{ ++ int i; ++ unsigned long flags; ++ struct urb *purb; ++ ++ struct sk_buff *pskb; ++ ++ struct r8180_priv *priv = (struct r8180_priv *)ieee80211_priv(dev); ++ ++ priv->tx_urb_index = 0; ++ ++ if ((!priv->rx_urb) || (!priv->pp_rxskb)) { ++ ++ DMESGE("Cannot intiate RX urb mechanism"); ++ return; ++ ++ } ++ ++ priv->rx_inx = 0; ++#ifdef THOMAS_TASKLET ++ atomic_set(&priv->irt_counter,0); ++#endif ++ for(i = 0;i < MAX_RX_URB; i++){ ++ ++ purb = priv->rx_urb[i] = usb_alloc_urb(0,GFP_KERNEL); ++ ++ if(!priv->rx_urb[i]) ++ goto destroy; ++ ++ pskb = priv->pp_rxskb[i] = dev_alloc_skb (RX_URB_SIZE); ++ ++ if (pskb == NULL) ++ goto destroy; ++ ++ purb->transfer_buffer_length = RX_URB_SIZE; ++ purb->transfer_buffer = pskb->data; ++ } ++ ++ spin_lock_irqsave(&priv->irq_lock,flags);//added by thomas ++ ++ for(i=0;i<MAX_RX_URB;i++) ++ rtl8187_rx_urbsubmit(dev,priv->rx_urb[i]); ++ ++ spin_unlock_irqrestore(&priv->irq_lock,flags);//added by thomas ++ ++ return; ++ ++destroy: ++ ++ for(i = 0; i < MAX_RX_URB; i++) { ++ ++ purb = priv->rx_urb[i]; ++ ++ if (purb) ++ usb_free_urb(purb); ++ ++ pskb = priv->pp_rxskb[i]; ++ ++ if (pskb) ++ dev_kfree_skb_any(pskb); ++ ++ } ++ ++ return; ++} ++ ++ ++void rtl8187_rx_manage_initiate(struct net_device *dev) ++{ ++ struct r8180_priv *priv = (struct r8180_priv *)ieee80211_priv(dev); ++ if(!priv->rx_urb) ++ DMESGE("Cannot intiate RX urb mechanism"); ++ ++ rtl8187_rx_manage_urbsubmit(dev,priv->rx_urb[MAX_RX_URB]); ++ ++} ++ ++ ++void rtl8187_set_rxconf(struct net_device *dev) ++{ ++ struct r8180_priv *priv = (struct r8180_priv *)ieee80211_priv(dev); ++ u32 rxconf; ++ ++ rxconf=read_nic_dword(dev,RX_CONF); ++ rxconf = rxconf &~ MAC_FILTER_MASK; ++ rxconf = rxconf | (1<<ACCEPT_MNG_FRAME_SHIFT); ++ rxconf = rxconf | (1<<ACCEPT_DATA_FRAME_SHIFT); ++ rxconf = rxconf | (1<<ACCEPT_BCAST_FRAME_SHIFT); ++ rxconf = rxconf | (1<<ACCEPT_MCAST_FRAME_SHIFT); ++ //rxconf = rxconf | (1<<ACCEPT_CTL_FRAME_SHIFT); ++#ifdef SW_ANTE_DIVERSITY ++ rxconf = rxconf | priv->EEPROMCSMethod;//for antenna ++#endif ++ ++ if (dev->flags & IFF_PROMISC) DMESG ("NIC in promisc mode"); ++ ++ if(priv->ieee80211->iw_mode == IW_MODE_MONITOR || \ ++ dev->flags & IFF_PROMISC){ ++ rxconf = rxconf | (1<<ACCEPT_ALLMAC_FRAME_SHIFT); ++ } /*else if(priv->ieee80211->iw_mode == IW_MODE_MASTER){ ++ rxconf = rxconf | (1<<ACCEPT_ALLMAC_FRAME_SHIFT); ++ rxconf = rxconf | (1<<RX_CHECK_BSSID_SHIFT); ++ }*/else{ ++ rxconf = rxconf | (1<<ACCEPT_NICMAC_FRAME_SHIFT); ++ rxconf = rxconf | (1<<RX_CHECK_BSSID_SHIFT); ++ } ++ ++ ++ if(priv->ieee80211->iw_mode == IW_MODE_MONITOR){ ++ rxconf = rxconf | (1<<ACCEPT_ICVERR_FRAME_SHIFT); ++ rxconf = rxconf | (1<<ACCEPT_PWR_FRAME_SHIFT); ++ } ++ ++ if( priv->crcmon == 1 && priv->ieee80211->iw_mode == IW_MODE_MONITOR) ++ rxconf = rxconf | (1<<ACCEPT_CRCERR_FRAME_SHIFT); ++ ++ ++ rxconf = rxconf &~ RX_FIFO_THRESHOLD_MASK; ++ rxconf = rxconf | (RX_FIFO_THRESHOLD_NONE<<RX_FIFO_THRESHOLD_SHIFT); ++ rxconf = rxconf &~ MAX_RX_DMA_MASK; ++ rxconf = rxconf | (MAX_RX_DMA_2048<<MAX_RX_DMA_SHIFT); ++ ++ rxconf = rxconf | (1<<RX_AUTORESETPHY_SHIFT); ++ rxconf = rxconf | RCR_ONLYERLPKT; ++ ++ //rxconf = rxconf &~ RCR_CS_MASK; ++ //rxconf = rxconf | (1<<RCR_CS_SHIFT); ++ ++ write_nic_dword(dev, RX_CONF, rxconf); ++ ++ #ifdef DEBUG_RX ++ DMESG("rxconf: %x %x",rxconf ,read_nic_dword(dev,RX_CONF)); ++ #endif ++} ++ ++void rtl8180_rx_enable(struct net_device *dev) ++{ ++ u8 cmd; ++ ++ struct r8180_priv *priv = (struct r8180_priv *)ieee80211_priv(dev); ++ ++ rtl8187_rx_initiate(dev); ++ rtl8187_set_rxconf(dev); ++ ++ if(NIC_8187 == priv->card_8187) { ++ cmd=read_nic_byte(dev,CMD); ++ write_nic_byte(dev,CMD,cmd | (1<<CMD_RX_ENABLE_SHIFT)); ++ } else { ++ //write_nic_dword(dev, RCR, priv->ReceiveConfig); ++ } ++} ++ ++ ++void rtl8180_tx_enable(struct net_device *dev) ++{ ++ u8 cmd; ++ u8 byte; ++ u32 txconf = 0; ++ struct r8180_priv *priv = (struct r8180_priv *)ieee80211_priv(dev); ++ ++ if(NIC_8187B == priv->card_8187){ ++ write_nic_dword(dev, TCR, priv->TransmitConfig); ++ byte = read_nic_byte(dev, MSR); ++ byte |= MSR_LINK_ENEDCA; ++ write_nic_byte(dev, MSR, byte); ++#ifdef LOOP_TEST ++ txconf= read_nic_dword(dev,TX_CONF); ++ txconf = txconf | (TX_LOOPBACK_MAC<<TX_LOOPBACK_SHIFT); ++ write_nic_dword(dev,TX_CONF,txconf); ++#endif ++ } else { ++ byte = read_nic_byte(dev,CW_CONF); ++ byte &= ~(1<<CW_CONF_PERPACKET_CW_SHIFT); ++ byte &= ~(1<<CW_CONF_PERPACKET_RETRY_SHIFT); ++ write_nic_byte(dev, CW_CONF, byte); ++ ++ byte = read_nic_byte(dev, TX_AGC_CTL); ++ byte &= ~(1<<TX_AGC_CTL_PERPACKET_GAIN_SHIFT); ++ byte &= ~(1<<TX_AGC_CTL_PERPACKET_ANTSEL_SHIFT); ++ byte &= ~(1<<TX_AGC_CTL_FEEDBACK_ANT); ++ write_nic_byte(dev, TX_AGC_CTL, byte); ++ ++ txconf= read_nic_dword(dev,TX_CONF); ++ ++ ++ txconf = txconf &~ TX_LOOPBACK_MASK; ++ ++#ifndef LOOP_TEST ++ txconf = txconf | (TX_LOOPBACK_NONE<<TX_LOOPBACK_SHIFT); ++#else ++ txconf = txconf | (TX_LOOPBACK_BASEBAND<<TX_LOOPBACK_SHIFT); ++#endif ++ txconf = txconf &~ TCR_SRL_MASK; ++ txconf = txconf &~ TCR_LRL_MASK; ++ ++ txconf = txconf | (priv->retry_data<<TX_LRLRETRY_SHIFT); // long ++ txconf = txconf | (priv->retry_rts<<TX_SRLRETRY_SHIFT); // short ++ ++ txconf = txconf &~ (1<<TX_NOCRC_SHIFT); ++ ++ txconf = txconf &~ TCR_MXDMA_MASK; ++ txconf = txconf | (TCR_MXDMA_2048<<TCR_MXDMA_SHIFT); ++ ++ txconf = txconf | TCR_DISReqQsize; ++ txconf = txconf | TCR_DISCW; ++ txconf = txconf &~ TCR_SWPLCPLEN; ++ ++ txconf=txconf | (1<<TX_NOICV_SHIFT); ++ ++ write_nic_dword(dev,TX_CONF,txconf); ++ ++#ifdef DEBUG_TX ++ DMESG("txconf: %x %x",txconf,read_nic_dword(dev,TX_CONF)); ++#endif ++ ++ cmd=read_nic_byte(dev,CMD); ++ write_nic_byte(dev,CMD,cmd | (1<<CMD_TX_ENABLE_SHIFT)); ++ } ++} ++ ++#if 0 ++void rtl8180_beacon_tx_enable(struct net_device *dev) ++{ ++ struct r8180_priv *priv = (struct r8180_priv *)ieee80211_priv(dev); ++ priv->dma_poll_mask &=~(1<<TX_DMA_STOP_BEACON_SHIFT); ++ rtl8180_set_mode(dev,EPROM_CMD_CONFIG); ++ write_nic_byte(dev,TX_DMA_POLLING,priv->dma_poll_mask); ++ rtl8180_set_mode(dev,EPROM_CMD_NORMAL); ++} ++ ++ ++void rtl8180_ ++_disable(struct net_device *dev) ++{ ++ struct r8180_priv *priv = (struct r8180_priv *)ieee80211_priv(dev); ++ priv->dma_poll_mask |= (1<<TX_DMA_STOP_BEACON_SHIFT); ++ rtl8180_set_mode(dev,EPROM_CMD_CONFIG); ++ write_nic_byte(dev,TX_DMA_POLLING,priv->dma_poll_mask); ++ rtl8180_set_mode(dev,EPROM_CMD_NORMAL); ++} ++ ++#endif ++ ++ ++void rtl8180_rtx_disable(struct net_device *dev) ++{ ++ u8 cmd; ++ int i; ++ struct r8180_priv *priv = ieee80211_priv(dev); ++ ++ cmd=read_nic_byte(dev,CMD); ++ write_nic_byte(dev, CMD, cmd &~ \ ++ ((1<<CMD_RX_ENABLE_SHIFT)|(1<<CMD_TX_ENABLE_SHIFT))); ++ force_pci_posting(dev); ++ mdelay(10); ++ ++#ifdef THOMAS_BEACON ++ { ++ int index = priv->rx_inx;//0 ++ i=0; ++ if(priv->rx_urb){ ++ while(i<MAX_RX_URB){ ++ if(priv->rx_urb[index]){ ++ usb_kill_urb(priv->rx_urb[index]); ++ } ++ if( index == (MAX_RX_URB-1) ) ++ index=0; ++ else ++ index=index+1; ++ i++; ++ } ++ if(priv->rx_urb[MAX_RX_URB]) ++ usb_kill_urb(priv->rx_urb[MAX_RX_URB]); ++ } ++ } ++#endif ++} ++ ++ ++int alloc_tx_beacon_desc_ring(struct net_device *dev, int count) ++{ ++ #if 0 ++ int i; ++ u32 *tmp; ++ struct r8180_priv *priv = (struct r8180_priv *)ieee80211_priv(dev); ++ ++ priv->txbeaconring = (u32*)pci_alloc_consistent(priv->pdev, ++ sizeof(u32)*8*count, ++ &priv->txbeaconringdma); ++ if (!priv->txbeaconring) return -1; ++ for (tmp=priv->txbeaconring,i=0;i<count;i++){ ++ *tmp = *tmp &~ (1<<31); // descriptor empty, owned by the drv ++ /* ++ *(tmp+2) = (u32)dma_tmp; ++ *(tmp+3) = bufsize; ++ */ ++ if(i+1<count) ++ *(tmp+4) = (u32)priv->txbeaconringdma+((i+1)*8*4); ++ else ++ *(tmp+4) = (u32)priv->txbeaconringdma; ++ ++ tmp=tmp+8; ++ } ++ #endif ++ return 0; ++} ++ ++long NetgearSignalStrengthTranslate(long LastSS,long CurrSS) ++{ ++ long RetSS; ++ ++ // Step 1. Scale mapping. ++ if(CurrSS >= 71 && CurrSS <= 100){ ++ RetSS = 90 + ((CurrSS - 70) / 3); ++ }else if(CurrSS >= 41 && CurrSS <= 70){ ++ RetSS = 78 + ((CurrSS - 40) / 3); ++ }else if(CurrSS >= 31 && CurrSS <= 40){ ++ RetSS = 66 + (CurrSS - 30); ++ }else if(CurrSS >= 21 && CurrSS <= 30){ ++ RetSS = 54 + (CurrSS - 20); ++ }else if(CurrSS >= 5 && CurrSS <= 20){ ++ RetSS = 42 + (((CurrSS - 5) * 2) / 3); ++ }else if(CurrSS == 4){ ++ RetSS = 36; ++ }else if(CurrSS == 3){ ++ RetSS = 27; ++ }else if(CurrSS == 2){ ++ RetSS = 18; ++ }else if(CurrSS == 1){ ++ RetSS = 9; ++ }else{ ++ RetSS = CurrSS; ++ } ++ //RT_TRACE(COMP_DBG, DBG_LOUD, ("##### After Mapping: LastSS: %d, CurrSS: %d, RetSS: %d\n", LastSS, CurrSS, RetSS)); ++ ++ // Step 2. Smoothing. ++ if(LastSS > 0){ ++ RetSS = ((LastSS * 5) + (RetSS)+ 5) / 6; ++ } ++ //RT_TRACE(COMP_DBG, DBG_LOUD, ("$$$$$ After Smoothing: LastSS: %d, CurrSS: %d, RetSS: %d\n", LastSS, CurrSS, RetSS)); ++ ++ return RetSS; ++} ++ ++extern long TranslateToDbm8187(u8 SignalStrengthIndex); // 0-100 index. ++//long TranslateToDbm8187(u8 SignalStrengthIndex) // 0-100 index. ++//{ ++ // long SignalPower; // in dBm. ++ ++ // Translate to dBm (x=0.5y-95). ++ // SignalPower = (long)((SignalStrengthIndex + 1) >> 1); ++ // SignalPower -= 95; ++ ++ // return SignalPower; ++//} ++ ++ ++void rtl8180_reset(struct net_device *dev) ++{ ++ ++ struct r8180_priv *priv = ieee80211_priv(dev); ++ u8 cr; ++ int i; ++ ++ ++ /* make sure the analog power is on before ++ * reset, otherwise reset may fail ++ */ ++ if(NIC_8187 == priv->card_8187) { ++ rtl8180_set_anaparam(dev, RTL8225_ANAPARAM_ON); ++ rtl8185_set_anaparam2(dev, RTL8225_ANAPARAM2_ON); ++ rtl8180_irq_disable(dev); ++ mdelay(200); ++ write_nic_byte_E(dev,0x18,0x10); ++ write_nic_byte_E(dev,0x18,0x11); ++ write_nic_byte_E(dev,0x18,0x00); ++ mdelay(200); ++ } ++ ++ ++ cr=read_nic_byte(dev,CMD); ++ cr = cr & 2; ++ cr = cr | (1<<CMD_RST_SHIFT); ++ write_nic_byte(dev,CMD,cr); ++ ++ //lzm mod for up take too long time 20081201 ++ //force_pci_posting(dev); ++ //mdelay(200); ++ udelay(20); ++ ++ if(read_nic_byte(dev,CMD) & (1<<CMD_RST_SHIFT)) ++ DMESGW("Card reset timeout!"); ++ ++ if(NIC_8187 == priv->card_8187) { ++ ++ //printk("This is RTL8187 Reset procedure\n"); ++ rtl8180_set_mode(dev,EPROM_CMD_LOAD); ++ force_pci_posting(dev); ++ mdelay(200); ++ ++ /* after the eeprom load cycle, make sure we have ++ * correct anaparams ++ */ ++ rtl8180_set_anaparam(dev, RTL8225_ANAPARAM_ON); ++ rtl8185_set_anaparam2(dev, RTL8225_ANAPARAM2_ON); ++ } ++ else { ++ //printk("This is RTL8187B Reset procedure\n"); ++ //test pending bug, john 20070815 ++ //initialize tx_pending ++ for(i=0;i<0x10;i++) atomic_set(&(priv->tx_pending[i]), 0); ++ ++ } ++ ++} ++ ++inline u16 ieeerate2rtlrate(int rate) ++{ ++ switch(rate){ ++ case 10: ++ return 0; ++ case 20: ++ return 1; ++ case 55: ++ return 2; ++ case 110: ++ return 3; ++ case 60: ++ return 4; ++ case 90: ++ return 5; ++ case 120: ++ return 6; ++ case 180: ++ return 7; ++ case 240: ++ return 8; ++ case 360: ++ return 9; ++ case 480: ++ return 10; ++ case 540: ++ return 11; ++ default: ++ return 3; ++ ++ } ++} ++static u16 rtl_rate[] = {10,20,55,110,60,90,120,180,240,360,480,540,720}; ++inline u16 rtl8180_rate2rate(short rate) ++{ ++ if (rate >12) return 10; ++ return rtl_rate[rate]; ++} ++ ++void rtl8180_irq_rx_tasklet(struct r8180_priv *priv); ++#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,20) ++void rtl8187_rx_isr(struct urb *rx_urb, struct pt_regs *regs) ++#else ++void rtl8187_rx_isr(struct urb* rx_urb) ++#endif ++{ ++ struct net_device *dev = (struct net_device*)rx_urb->context; ++ struct r8180_priv *priv = ieee80211_priv(dev); ++ priv->rxurb_task = rx_urb; ++ ++ ++ //DMESGW("David: Rx tasklet start!"); ++ ++#ifdef THOMAS_TASKLET ++ atomic_inc( &priv->irt_counter ); ++ ++ //if( likely(priv->irt_counter_head+1 != priv->irt_counter_tail) ){ ++ // priv->irt_counter_head = (priv->irt_counter_head+1)&0xffff ; ++ tasklet_schedule(&priv->irq_rx_tasklet); ++ //} else{ ++ //DMESG("error: priv->irt_counter_head is going to pass through priv->irt_counter_tail\n"); ++ /* ++ skb = priv->pp_rxskb[priv->rx_inx]; ++ dev_kfree_skb_any(skb); ++ ++ skb = dev_alloc_skb(RX_URB_SIZE); ++ if (skb == NULL) ++ panic("No Skb For RX!/n"); ++ ++ rx_urb->transfer_buffer = skb->data; ++ ++ priv->pp_rxskb[priv->rx_inx] = skb; ++ if(status == 0) ++ rtl8187_rx_urbsubmit(dev,rx_urb); ++ else { ++ priv->pp_rxskb[priv->rx_inx] = NULL; ++ dev_kfree_skb_any(skb); ++ printk("RX process aborted due to explicit shutdown (%x) ", status); ++ } ++ ++ if (*prx_inx == (MAX_RX_URB -1)) ++ *prx_inx = 0; ++ else ++ *prx_inx = *prx_inx + 1; ++ ++ */ ++ //} ++#endif ++ ++} ++ ++#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,20) ++void rtl8187_rx_manage_isr(struct urb *rx_urb, struct pt_regs *regs) ++#else ++void rtl8187_rx_manage_isr(struct urb* rx_urb) ++#endif ++{ ++ struct net_device *dev = (struct net_device*)rx_urb->context; ++ struct r8180_priv *priv = ieee80211_priv(dev); ++ int status,cmd; ++ struct sk_buff *skb; ++ u32 *desc; ++ int ret; ++ unsigned long flag; ++ ++ //DMESG("RX %d ",rx_urb->status); ++ status = rx_urb->status; ++ if(status == 0){ ++ ++ desc = (u32*)(rx_urb->transfer_buffer); ++ cmd = (desc[0] >> 30) & 0x03; ++ //printk(KERN_ALERT "buffersize = %d, length = %d, pipe = %p\n", ++ //rx_urb->transfer_buffer_length, rx_urb->actual_length, rx_urb->pipe>>15); ++ ++ if(cmd == 0x00) {//beacon interrupt ++ //send beacon packet ++ ++ spin_lock_irqsave(&priv->ieee80211->beaconflag_lock,flag); ++ if(priv->flag_beacon == true){ ++ //printk("rtl8187_rx_manage_isr(): CMD_TYPE0_BCN_INTR\n"); ++ ++ skb = ieee80211_get_beacon(priv->ieee80211); ++ if(!skb){ ++ DMESG("not enought memory for allocating beacon"); ++ return; ++ } ++ //printk(KERN_WARNING "to send beacon packet through beacon endpoint!\n"); ++ ret = rtl8180_tx(dev, (u32*)skb->data, skb->len, BEACON_PRIORITY, ++ 0, ieeerate2rtlrate(priv->ieee80211->basic_rate)); ++ ++ if( ret != 0 ){ ++ printk(KERN_ALERT "tx beacon packet error : %d !\n", ret); ++ } ++ dev_kfree_skb_any(skb); ++ ++ //} else {//0x00 ++ //{ log the device information ++ // At present, It is not implemented just now. ++ //} ++ //} ++ ++ } ++ spin_unlock_irqrestore(&priv->ieee80211->beaconflag_lock,flag); ++ } ++ else if(cmd == 0x01){ ++ //printk("rtl8187_rx_manage_isr(): CMD_TYPE1_TX_CLOSE\n"); ++ priv->CurrRetryCnt += (u16)desc[0]&0x000000ff; ++ //printk("priv->CurrRetryCnt is %d\n",priv->CurrRetryCnt); ++ } ++ else ++ printk("HalUsbInCommandComplete8187B(): unknown Type(%#X) !!!\n", cmd); ++ ++ }else{ ++ priv->stats.rxstaterr++; ++ priv->ieee80211->stats.rx_errors++; ++ } ++ ++ ++ if( status == 0 ) ++ //if(status != -ENOENT) ++ rtl8187_rx_manage_urbsubmit(dev, rx_urb); ++ else ++ ;//DMESG("Mangement RX process aborted due to explicit shutdown"); ++} ++ ++#if 0 ++void rtl8180_tx_queues_stop(struct net_device *dev) ++{ ++ //struct r8180_priv *priv = (struct r8180_priv *)ieee80211_priv(dev); ++ u8 dma_poll_mask = (1<<TX_DMA_STOP_LOWPRIORITY_SHIFT); ++ dma_poll_mask |= (1<<TX_DMA_STOP_HIPRIORITY_SHIFT); ++ dma_poll_mask |= (1<<TX_DMA_STOP_NORMPRIORITY_SHIFT); ++ dma_poll_mask |= (1<<TX_DMA_STOP_BEACON_SHIFT); ++ ++ rtl8180_set_mode(dev,EPROM_CMD_CONFIG); ++ write_nic_byte(dev,TX_DMA_POLLING,dma_poll_mask); ++ rtl8180_set_mode(dev,EPROM_CMD_NORMAL); ++} ++#endif ++ ++void rtl8180_data_hard_stop(struct net_device *dev) ++{ ++ //FIXME !! ++ #if 0 ++ struct r8180_priv *priv = (struct r8180_priv *)ieee80211_priv(dev); ++ priv->dma_poll_mask |= (1<<TX_DMA_STOP_LOWPRIORITY_SHIFT); ++ rtl8180_set_mode(dev,EPROM_CMD_CONFIG); ++ write_nic_byte(dev,TX_DMA_POLLING,priv->dma_poll_mask); ++ rtl8180_set_mode(dev,EPROM_CMD_NORMAL); ++ #endif ++} ++ ++ ++void rtl8180_data_hard_resume(struct net_device *dev) ++{ ++ // FIXME !! ++ #if 0 ++ struct r8180_priv *priv = (struct r8180_priv *)ieee80211_priv(dev); ++ priv->dma_poll_mask &= ~(1<<TX_DMA_STOP_LOWPRIORITY_SHIFT); ++ rtl8180_set_mode(dev,EPROM_CMD_CONFIG); ++ write_nic_byte(dev,TX_DMA_POLLING,priv->dma_poll_mask); ++ rtl8180_set_mode(dev,EPROM_CMD_NORMAL); ++ #endif ++} ++ ++unsigned int PRI2EP[4] = {0x06,0x07,0x05,0x04}; ++// this function TX data frames when the ieee80211 stack requires this. ++// It checks also if we need to stop the ieee tx queue, eventually do it ++void rtl8180_hard_data_xmit(struct sk_buff *skb, struct net_device *dev, int rate) ++{ ++ struct r8180_priv *priv = (struct r8180_priv *)ieee80211_priv(dev); ++ ++ short morefrag = 0; ++ unsigned long flags; ++ struct ieee80211_hdr *h = (struct ieee80211_hdr *) skb->data; ++ ++ unsigned char ep; ++ short ret; //john ++ ++ if (le16_to_cpu(h->frame_ctl) & IEEE80211_FCTL_MOREFRAGS) ++ morefrag = 1; ++ //DMESG("%x %x", h->frame_ctl, h->seq_ctl); ++ /* ++ * This function doesn't require lock because we make ++ * sure it's called with the tx_lock already acquired. ++ * this come from the kernel's hard_xmit callback (trought ++ * the ieee stack, or from the try_wake_queue (again trought ++ * the ieee stack. ++ */ ++ spin_lock_irqsave(&priv->tx_lock,flags); ++ ++ //lzm mod 20081128 for sometimes wlan down but it still have some pkt to tx ++ if((priv->ieee80211->bHwRadioOff)||(!priv->up)) ++ { ++ spin_unlock_irqrestore(&priv->tx_lock,flags); ++ ++ return; ++ } ++ ++ if(NIC_8187B == priv->card_8187){ ++ ep = PRI2EP[skb->priority]; ++ } else { ++ ep = LOW_PRIORITY; ++ } ++ //if (!check_nic_enought_desc(dev, PRI2EP[skb->priority])){ ++ if (!check_nic_enought_desc(dev, ep)){ ++ DMESG("Error: no TX slot "); ++ ieee80211_stop_queue(priv->ieee80211); ++ } ++ ++#ifdef LED_SHIN ++ priv->ieee80211->ieee80211_led_contorl(dev,LED_CTL_TX); ++#endif ++ ++ ret = rtl8180_tx(dev, (u32*)skb->data, skb->len, ep, morefrag,ieeerate2rtlrate(rate)); ++ if(ret!=0) DMESG("Error: rtl8180_tx failed in rtl8180_hard_data_xmit\n");//john ++ ++ priv->stats.txdatapkt++; ++ ++ //if (!check_nic_enought_desc(dev, PRI2EP[skb->priority])){ ++ if (!check_nic_enought_desc(dev, ep)){ ++ ieee80211_stop_queue(priv->ieee80211); ++ } ++ ++ spin_unlock_irqrestore(&priv->tx_lock,flags); ++ ++} ++ ++//This is a rough attempt to TX a frame ++//This is called by the ieee 80211 stack to TX management frames. ++//If the ring is full packet are dropped (for data frame the queue ++//is stopped before this can happen). ++ ++int rtl8180_hard_start_xmit(struct sk_buff *skb,struct net_device *dev) ++{ ++ struct r8180_priv *priv = (struct r8180_priv *)ieee80211_priv(dev); ++ struct ieee80211_device *ieee = priv->ieee80211; ++ int ret; ++ unsigned long flags; ++ spin_lock_irqsave(&priv->tx_lock,flags); ++ ++ //lzm mod 20081128 for sometimes wlan down but it still have some pkt to tx ++ if((priv->ieee80211->bHwRadioOff)||(!priv->up)) ++ { ++ spin_unlock_irqrestore(&priv->tx_lock,flags); ++ return 0; ++ } ++ ++ ret = rtl8180_tx(dev, (u32*)skb->data, skb->len, MANAGE_PRIORITY, 0, ieeerate2rtlrate(ieee->basic_rate)); ++ ++ priv->ieee80211->stats.tx_bytes+=skb->len; ++ priv->ieee80211->stats.tx_packets++; ++ ++ spin_unlock_irqrestore(&priv->tx_lock,flags); ++ ++ return ret; ++} ++ ++ ++#if 0 ++// longpre 144+48 shortpre 72+24 ++u16 rtl8180_len2duration(u32 len, short rate,short* ext) ++{ ++ u16 duration; ++ u16 drift; ++ *ext=0; ++ ++ switch(rate){ ++ case 0://1mbps ++ *ext=0; ++ duration = ((len+4)<<4) /0x2; ++ drift = ((len+4)<<4) % 0x2; ++ if(drift ==0 ) break; ++ duration++; ++ break; ++ ++ case 1://2mbps ++ *ext=0; ++ duration = ((len+4)<<4) /0x4; ++ drift = ((len+4)<<4) % 0x4; ++ if(drift ==0 ) break; ++ duration++; ++ break; ++ ++ case 2: //5.5mbps ++ *ext=0; ++ duration = ((len+4)<<4) /0xb; ++ drift = ((len+4)<<4) % 0xb; ++ if(drift ==0 ) ++ break; ++ duration++; ++ break; ++ ++ default: ++ case 3://11mbps ++ *ext=0; ++ duration = ((len+4)<<4) /0x16; ++ drift = ((len+4)<<4) % 0x16; ++ if(drift ==0 ) ++ break; ++ duration++; ++ if(drift > 6) ++ break; ++ *ext=1; ++ break; ++ } ++ ++ return duration; ++} ++#endif ++ ++void rtl8180_try_wake_queue(struct net_device *dev, int pri); ++ ++#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,20) ++void rtl8187_lptx_isr(struct urb *tx_urb, struct pt_regs *regs) ++#else ++void rtl8187_lptx_isr(struct urb* tx_urb) ++#endif ++{ ++ struct net_device *dev = (struct net_device*)tx_urb->context; ++ struct r8180_priv *priv = ieee80211_priv(dev); ++ ++ if(tx_urb->status == 0){ ++ dev->trans_start = jiffies; //john ++ priv->stats.txlpokint++; ++ priv->txokbytestotal+=tx_urb->actual_length; ++ }else{ ++ priv->stats.txlperr++; ++ } ++ ++ kfree(tx_urb->transfer_buffer); ++ usb_free_urb(tx_urb); ++ ++ if(atomic_read(&priv->tx_pending[LOW_PRIORITY]) >= 1) ++ atomic_dec(&priv->tx_pending[LOW_PRIORITY]); ++ ++ rtl8180_try_wake_queue(dev,LOW_PRIORITY); ++} ++ ++#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,20) ++void rtl8187_nptx_isr(struct urb *tx_urb, struct pt_regs *regs) ++#else ++void rtl8187_nptx_isr(struct urb* tx_urb) ++#endif ++{ ++ struct net_device *dev = (struct net_device*)tx_urb->context; ++ struct r8180_priv *priv = ieee80211_priv(dev); ++ ++ if(tx_urb->status == 0){ ++ dev->trans_start = jiffies; //john ++ priv->stats.txnpokint++; ++ }else{ ++ priv->stats.txnperr++; ++ } ++ ++ kfree(tx_urb->transfer_buffer); ++ usb_free_urb(tx_urb); ++ ++ if(atomic_read(&priv->tx_pending[NORM_PRIORITY]) >= 1) ++ atomic_dec(&priv->tx_pending[NORM_PRIORITY]); ++ //rtl8180_try_wake_queue(dev,NORM_PRIORITY); ++} ++ ++#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,20) ++void rtl8187_votx_isr(struct urb *tx_urb, struct pt_regs *regs) ++#else ++void rtl8187_votx_isr(struct urb* tx_urb) ++#endif ++{ ++ struct net_device *dev = (struct net_device*)tx_urb->context; ++ struct r8180_priv *priv = ieee80211_priv(dev); ++ ++ if(tx_urb->status == 0){ ++ dev->trans_start = jiffies; //john ++ priv->stats.txvookint++; ++ priv->txokbytestotal+=tx_urb->actual_length; ++ }else{ ++ priv->stats.txvoerr++; ++ } ++ ++ kfree(tx_urb->transfer_buffer); ++ usb_free_urb(tx_urb); ++ ++ if(atomic_read(&priv->tx_pending[VO_PRIORITY]) >= 1) ++ atomic_dec(&priv->tx_pending[VO_PRIORITY]); ++ rtl8180_try_wake_queue(dev,VO_PRIORITY); ++} ++ ++#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,20) ++void rtl8187_vitx_isr(struct urb *tx_urb, struct pt_regs *regs) ++#else ++void rtl8187_vitx_isr(struct urb* tx_urb) ++#endif ++{ ++ struct net_device *dev = (struct net_device*)tx_urb->context; ++ struct r8180_priv *priv = ieee80211_priv(dev); ++ ++ if(tx_urb->status == 0){ ++ dev->trans_start = jiffies; //john ++ priv->stats.txviokint++; ++ priv->txokbytestotal+=tx_urb->actual_length; ++ }else{ ++ priv->stats.txvierr++; ++ } ++ ++ kfree(tx_urb->transfer_buffer); ++ usb_free_urb(tx_urb); ++ ++ if(atomic_read(&priv->tx_pending[VI_PRIORITY]) >= 1) ++ atomic_dec(&priv->tx_pending[VI_PRIORITY]); ++ rtl8180_try_wake_queue(dev,VI_PRIORITY); ++} ++ ++#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,20) ++void rtl8187_betx_isr(struct urb *tx_urb, struct pt_regs *regs) ++#else ++void rtl8187_betx_isr(struct urb* tx_urb) ++#endif ++{ ++ struct net_device *dev = (struct net_device*)tx_urb->context; ++ struct r8180_priv *priv = ieee80211_priv(dev); ++ ++ if(tx_urb->status == 0){ ++ dev->trans_start = jiffies; //john ++ priv->stats.txbeokint++; ++ priv->txokbytestotal+=tx_urb->actual_length; ++ }else{ ++ priv->stats.txbeerr++; ++ } ++ ++ kfree(tx_urb->transfer_buffer); ++ usb_free_urb(tx_urb); ++ ++ if(atomic_read(&priv->tx_pending[BE_PRIORITY]) >= 1) ++ atomic_dec(&priv->tx_pending[BE_PRIORITY]); ++ rtl8180_try_wake_queue(dev, BE_PRIORITY); ++} ++ ++#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,20) ++void rtl8187_bktx_isr(struct urb *tx_urb, struct pt_regs *regs) ++#else ++void rtl8187_bktx_isr(struct urb* tx_urb) ++#endif ++{ ++ struct net_device *dev = (struct net_device*)tx_urb->context; ++ struct r8180_priv *priv = ieee80211_priv(dev); ++ ++ if(tx_urb->status == 0){ ++ dev->trans_start = jiffies; //john ++ priv->stats.txbkokint++; ++ }else{ ++ priv->stats.txbkerr++; ++ } ++ ++ kfree(tx_urb->transfer_buffer); ++ usb_free_urb(tx_urb); ++ ++ if(atomic_read(&priv->tx_pending[BK_PRIORITY]) >= 1) ++ atomic_dec(&priv->tx_pending[BK_PRIORITY]); ++ rtl8180_try_wake_queue(dev,BK_PRIORITY); ++} ++ ++#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,20) ++void rtl8187_beacontx_isr(struct urb *tx_urb, struct pt_regs *regs) ++#else ++void rtl8187_beacontx_isr(struct urb* tx_urb) ++#endif ++{ ++ struct net_device *dev = (struct net_device*)tx_urb->context; ++ struct r8180_priv *priv = ieee80211_priv(dev); ++ ++ if(tx_urb->status == 0){ ++ dev->trans_start = jiffies; //john ++ priv->stats.txbeaconokint++; ++ priv->txokbytestotal+=tx_urb->actual_length; ++ }else{ ++ priv->stats.txbeaconerr++; ++ } ++ ++ kfree(tx_urb->transfer_buffer); ++ usb_free_urb(tx_urb); ++ ++ if(atomic_read(&priv->tx_pending[BEACON_PRIORITY]) >= 1) ++ atomic_dec(&priv->tx_pending[BEACON_PRIORITY]); ++ //rtl8180_try_wake_queue(dev,BEACON_PRIORITY); ++} ++ ++#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,20) ++void rtl8187_managetx_isr(struct urb *tx_urb, struct pt_regs *regs) ++#else ++void rtl8187_managetx_isr(struct urb* tx_urb) ++#endif ++{ ++ struct net_device *dev = (struct net_device*)tx_urb->context; ++ struct r8180_priv *priv = ieee80211_priv(dev); ++ ++ if(tx_urb->status == 0){ ++ dev->trans_start = jiffies; //john ++ priv->stats.txmanageokint++; ++ priv->txokbytestotal+=tx_urb->actual_length; ++ }else{ ++ priv->stats.txmanageerr++; ++ } ++ ++ kfree(tx_urb->transfer_buffer); ++ usb_free_urb(tx_urb); ++ ++ if(atomic_read(&priv->tx_pending[MANAGE_PRIORITY]) >= 1) ++ atomic_dec(&priv->tx_pending[MANAGE_PRIORITY]); ++// rtl8180_try_wake_queue(dev,MANAGE_PRIORITY); ++} ++ ++void rtl8187_beacon_stop(struct net_device *dev) ++{ ++ u8 msr, msrm, msr2; ++ struct r8180_priv *priv = ieee80211_priv(dev); ++ unsigned long flag; ++ msr = read_nic_byte(dev, MSR); ++ msrm = msr & MSR_LINK_MASK; ++ msr2 = msr & ~MSR_LINK_MASK; ++ if(NIC_8187B == priv->card_8187) { ++ spin_lock_irqsave(&priv->ieee80211->beaconflag_lock,flag); ++ priv->flag_beacon = false; ++ spin_unlock_irqrestore(&priv->ieee80211->beaconflag_lock,flag); ++ } ++ if ((msrm == (MSR_LINK_ADHOC<<MSR_LINK_SHIFT) || ++ (msrm == (MSR_LINK_MASTER<<MSR_LINK_SHIFT)))){ ++ write_nic_byte(dev, MSR, msr2 | MSR_LINK_NONE); ++ write_nic_byte(dev, MSR, msr); ++ } ++} ++ ++ ++void rtl8187_net_update(struct net_device *dev) ++{ ++ ++ struct r8180_priv *priv = ieee80211_priv(dev); ++ struct ieee80211_network *net; ++ net = & priv->ieee80211->current_network; ++ ++ ++ write_nic_dword(dev,BSSID,((u32*)net->bssid)[0]); ++ write_nic_word(dev,BSSID+4,((u16*)net->bssid)[2]); ++ ++ rtl8180_update_msr(dev); ++ ++ //rtl8180_set_mode(dev,EPROM_CMD_CONFIG); ++ write_nic_word(dev, AtimWnd, 2); ++ write_nic_word(dev, AtimtrItv, 100); ++ write_nic_word(dev, BEACON_INTERVAL, net->beacon_interval); ++ //write_nic_word(dev, BcnIntTime, 100); ++ write_nic_word(dev, BcnIntTime, 0x3FF); ++ ++ ++} ++ ++void rtl8187_beacon_tx(struct net_device *dev) ++{ ++ struct r8180_priv *priv = ieee80211_priv(dev); ++ struct sk_buff *skb; ++ int i = 0; ++ u8 cr; ++ unsigned long flag; ++ rtl8187_net_update(dev); ++ ++ if(NIC_8187B == priv->card_8187) { ++ //Cause TSF timer of MAC reset to 0 ++ cr=read_nic_byte(dev,CMD); ++ cr = cr | (1<<CMD_RST_SHIFT); ++ write_nic_byte(dev,CMD,cr); ++ ++ //lzm mod 20081201 ++ //mdelay(200); ++ mdelay(20); ++ ++ if(read_nic_byte(dev,CMD) & (1<<CMD_RST_SHIFT)) ++ DMESGW("Card reset timeout for ad-hoc!"); ++ else ++ DMESG("Card successfully reset for ad-hoc"); ++ ++ write_nic_byte(dev,CMD, (read_nic_byte(dev,CMD)|CR_RE|CR_TE)); ++ spin_lock_irqsave(&priv->ieee80211->beaconflag_lock,flag); ++ priv->flag_beacon = true; ++ spin_unlock_irqrestore(&priv->ieee80211->beaconflag_lock,flag); ++ ++ //rtl8187_rx_manage_initiate(dev); ++ } else { ++ printk(KERN_WARNING "get the beacon!\n"); ++ skb = ieee80211_get_beacon(priv->ieee80211); ++ if(!skb){ ++ DMESG("not enought memory for allocating beacon"); ++ return; ++ } ++ ++ write_nic_byte(dev, BQREQ, read_nic_byte(dev, BQREQ) | (1<<7)); ++ ++ i=0; ++ //while(!read_nic_byte(dev,BQREQ & (1<<7))) ++ while( (read_nic_byte(dev, BQREQ) & (1<<7)) == 0 ) ++ { ++ msleep_interruptible_rtl(HZ/2); ++ if(i++ > 10){ ++ DMESGW("get stuck to wait HW beacon to be ready"); ++ return ; ++ } ++ } ++ //tx ++ rtl8180_tx(dev, (u32*)skb->data, skb->len, NORM_PRIORITY, ++ 0, ieeerate2rtlrate(priv->ieee80211->basic_rate)); ++ if(skb) ++ dev_kfree_skb_any(skb); ++ } ++} ++ ++#if 0 ++void rtl8187_nptx_isr(struct urb *tx_urb, struct pt_regs *regs) ++{ ++ struct net_device *dev = (struct net_device*)tx_urb->context; ++ struct r8180_priv *priv = ieee80211_priv(dev); ++ ++ if(tx_urb->status == 0) ++ priv->stats.txnpokint++; ++ else ++ priv->stats.txnperr++; ++ kfree(tx_urb->transfer_buffer); ++ usb_free_urb(tx_urb); ++ atomic_dec(&priv->tx_np_pending); ++ //rtl8180_try_wake_queue(dev,NORM_PRIORITY); ++} ++#endif ++inline u8 rtl8180_IsWirelessBMode(u16 rate) ++{ ++ if( ((rate <= 110) && (rate != 60) && (rate != 90)) || (rate == 220) ) ++ return 1; ++ else return 0; ++} ++ ++u16 N_DBPSOfRate(u16 DataRate); ++ ++u16 ComputeTxTime( ++ u16 FrameLength, ++ u16 DataRate, ++ u8 bManagementFrame, ++ u8 bShortPreamble ++ ) ++{ ++ u16 FrameTime; ++ u16 N_DBPS; ++ u16 Ceiling; ++ ++ if( rtl8180_IsWirelessBMode(DataRate) ) ++ { ++ if( bManagementFrame || !bShortPreamble || DataRate == 10 ){ // long preamble ++ FrameTime = (u16)(144+48+(FrameLength*8/(DataRate/10))); ++ }else{ // Short preamble ++ FrameTime = (u16)(72+24+(FrameLength*8/(DataRate/10))); ++ } ++ if( ( FrameLength*8 % (DataRate/10) ) != 0 ) //Get the Ceilling ++ FrameTime ++; ++ } else { //802.11g DSSS-OFDM PLCP length field calculation. ++ N_DBPS = N_DBPSOfRate(DataRate); ++ Ceiling = (16 + 8*FrameLength + 6) / N_DBPS ++ + (((16 + 8*FrameLength + 6) % N_DBPS) ? 1 : 0); ++ FrameTime = (u16)(16 + 4 + 4*Ceiling + 6); ++ } ++ return FrameTime; ++} ++ ++u16 N_DBPSOfRate(u16 DataRate) ++{ ++ u16 N_DBPS = 24; ++ ++ switch(DataRate) ++ { ++ case 60: ++ N_DBPS = 24; ++ break; ++ ++ case 90: ++ N_DBPS = 36; ++ break; ++ ++ case 120: ++ N_DBPS = 48; ++ break; ++ ++ case 180: ++ N_DBPS = 72; ++ break; ++ ++ case 240: ++ N_DBPS = 96; ++ break; ++ ++ case 360: ++ N_DBPS = 144; ++ break; ++ ++ case 480: ++ N_DBPS = 192; ++ break; ++ ++ case 540: ++ N_DBPS = 216; ++ break; ++ ++ default: ++ break; ++ } ++ ++ return N_DBPS; ++} ++// NOte!!! ++// the rate filled in is the rtl_rate. ++// while the priv->ieee80211->basic_rate,used in the following code is ieee80211 rate. ++ ++#ifdef JUST_FOR_87SEMESH ++#define ActionHeadLen 30 ++#endif ++#define sCrcLng 4 ++#define sAckCtsLng 112 // bits in ACK and CTS frames ++short rtl8180_tx(struct net_device *dev, u32* txbuf, int len, priority_t priority, ++ short morefrag, short rate) ++{ ++ u32 *tx; ++ int pend ; ++ int status; ++ struct urb *tx_urb; ++ int urb_len; ++ struct r8180_priv *priv = ieee80211_priv(dev); ++ struct ieee80211_hdr_3addr_QOS *frag_hdr = (struct ieee80211_hdr_3addr_QOS *)txbuf; ++ struct ieee80211_device *ieee;//added for descriptor ++ u8 dest[ETH_ALEN]; ++ ++ bool bUseShortPreamble = false; ++ bool bCTSEnable = false; ++ bool bRTSEnable = false; ++ u16 Duration = 0; ++ u16 RtsDur = 0; ++ u16 ThisFrameTime = 0; ++ u16 TxDescDuration = 0; ++ ++ ieee = priv->ieee80211; ++#if 0 ++//{added by david for filter the packet listed in the filter table ++#ifdef _RTL8187_EXT_PATCH_ ++ if((ieee->iw_mode == ieee->iw_ext_mode) && (ieee->ext_patch_ieee80211_acl_query)) ++ { ++ if(!ieee->ext_patch_ieee80211_acl_query(ieee, frag_hdr->addr1)) { ++ return 0; ++ } ++ } ++#endif ++//} ++#endif ++ ++#ifdef JUST_FOR_87SEMESH ++//#ifdef Lawrence_Mesh ++ u8* meshtype = (u8*)txbuf; ++ if(*meshtype == 0xA8) ++ { ++ //overflow?? ++ //memcpy(meshtype+ActionHeadLen+2,meshtype+ActionHeadLen,Len-ActionHeadLen); ++ //memcpy(meshtype+ActionHeadLen,0,2); ++ u8 actionframe[256]; ++ memset(actionframe,0,256); ++ memcpy(actionframe,meshtype,ActionHeadLen); ++ memcpy(actionframe+ActionHeadLen+2,meshtype+ActionHeadLen,len-ActionHeadLen); ++ txbuf = (u32*)actionframe; ++ len=len+2; ++ frag_hdr = (struct ieee80211_hdr_3addr_QOS *)txbuf; ++ } ++#endif ++ ++ //pend = atomic_read((priority == NORM_PRIORITY)? &priv->tx_np_pending : &priv->tx_lp_pending); ++ pend = atomic_read(&priv->tx_pending[priority]); ++ /* we are locked here so the two atomic_read and inc are executed without interleaves */ ++ if( pend > MAX_TX_URB){ ++ if(NIC_8187 == priv->card_8187) { ++ if(priority == NORM_PRIORITY) ++ priv->stats.txnpdrop++; ++ else ++ priv->stats.txlpdrop++; ++ ++ } else { ++ switch (priority) { ++ case VO_PRIORITY: ++ priv->stats.txvodrop++; ++ break; ++ case VI_PRIORITY: ++ priv->stats.txvidrop++; ++ break; ++ case BE_PRIORITY: ++ priv->stats.txbedrop++; ++ break; ++ case MANAGE_PRIORITY: //lzm for MANAGE_PRIORITY pending ++ if(priv->commit == 0) ++ { ++ priv->commit = 1; ++ printk(KERN_INFO "manage pkt pending will commit now....\n"); ++#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0)) ++ schedule_work(&priv->reset_wq); ++#else ++ schedule_task(&priv->reset_wq); ++#endif ++ } ++ break; ++ default://BK_PRIORITY ++ priv->stats.txbkdrop++; ++ break; ++ } ++ } ++ //printk(KERN_INFO "tx_pending: %d > MAX_TX_URB\n", priority); ++ return -1; ++ } ++ ++ urb_len = len + ((NIC_8187 == priv->card_8187)?(4*3):(4*8)); ++ if((0 == (urb_len&63))||(0 == (urb_len&511))) { ++ urb_len += 1; ++ } ++ ++ tx = kmalloc(urb_len, GFP_ATOMIC); ++ if(!tx) return -ENOMEM; ++ memset(tx, 0, sizeof(u32) * 8); ++ ++#if LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0) ++ tx_urb = usb_alloc_urb(0,GFP_ATOMIC); ++#else ++ tx_urb = usb_alloc_urb(0); ++#endif ++ ++ if(!tx_urb){ ++ kfree(tx); ++ return -ENOMEM; ++ } ++ ++ // Check multicast/broadcast ++ if (ieee->iw_mode == IW_MODE_INFRA) { ++ /* To DS: Addr1 = BSSID, Addr2 = SA, ++ Addr3 = DA */ ++ //memcpy(&dest, frag_hdr->addr3, ETH_ALEN); ++ memcpy(&dest, frag_hdr->addr1, ETH_ALEN); ++ } else if (ieee->iw_mode == IW_MODE_ADHOC) { ++ /* not From/To DS: Addr1 = DA, Addr2 = SA, ++ Addr3 = BSSID */ ++ memcpy(&dest, frag_hdr->addr1, ETH_ALEN); ++ } ++ ++ if (is_multicast_ether_addr(dest) ||is_broadcast_ether_addr(dest)) ++ { ++ Duration = 0; ++ RtsDur = 0; ++ bRTSEnable = false; ++ bCTSEnable = false; ++ ++ ThisFrameTime = ComputeTxTime(len + sCrcLng, rtl8180_rate2rate(rate), false, bUseShortPreamble); ++ TxDescDuration = ThisFrameTime; ++ } else {// Unicast packet ++ //u8 AckRate; ++ u16 AckTime; ++ ++ // Figure out ACK rate according to BSS basic rate and Tx rate, 2006.03.08 by rcnjko. ++ //AckRate = ComputeAckRate( pMgntInfo->mBrates, (u1Byte)(pTcb->DataRate) ); ++ // Figure out ACK time according to the AckRate and assume long preamble is used on receiver, 2006.03.08, by rcnjko. ++ //AckTime = ComputeTxTime( sAckCtsLng/8, AckRate, FALSE, FALSE); ++ //For simplicity, just use the 1M basic rate ++ AckTime = ComputeTxTime(14, 10,false, false); // AckCTSLng = 14 use 1M bps send ++ //AckTime = ComputeTxTime(14, 2,false, false); // AckCTSLng = 14 use 1M bps send ++ ++ if ( ((len + sCrcLng) > priv->rts) && priv->rts ){ // RTS/CTS. ++ u16 RtsTime, CtsTime; ++ //u16 CtsRate; ++ bRTSEnable = true; ++ bCTSEnable = false; ++ ++ // Rate and time required for RTS. ++ RtsTime = ComputeTxTime( sAckCtsLng/8,priv->ieee80211->basic_rate, false, false); ++ // Rate and time required for CTS. ++ CtsTime = ComputeTxTime(14, 10,false, false); // AckCTSLng = 14 use 1M bps send ++ ++ // Figure out time required to transmit this frame. ++ ThisFrameTime = ComputeTxTime(len + sCrcLng, ++ rtl8180_rate2rate(rate), ++ false, ++ bUseShortPreamble); ++ ++ // RTS-CTS-ThisFrame-ACK. ++ RtsDur = CtsTime + ThisFrameTime + AckTime + 3*aSifsTime; ++ ++ TxDescDuration = RtsTime + RtsDur; ++ }else {// Normal case. ++ bCTSEnable = false; ++ bRTSEnable = false; ++ RtsDur = 0; ++ ++ ThisFrameTime = ComputeTxTime(len + sCrcLng, rtl8180_rate2rate(rate), false, bUseShortPreamble); ++ TxDescDuration = ThisFrameTime + aSifsTime + AckTime; ++ } ++ ++ if(!(frag_hdr->frame_ctl & IEEE80211_FCTL_MOREFRAGS)) { //no more fragment ++ // ThisFrame-ACK. ++ Duration = aSifsTime + AckTime; ++ } else { // One or more fragments remained. ++ u16 NextFragTime; ++ NextFragTime = ComputeTxTime( len + sCrcLng, //pretend following packet length equal current packet ++ rtl8180_rate2rate(rate), ++ false, bUseShortPreamble ); ++ ++ //ThisFrag-ACk-NextFrag-ACK. ++ Duration = NextFragTime + 3*aSifsTime + 2*AckTime; ++ } ++ ++ } // End of Unicast packet ++ ++ ++ //fill the tx desriptor ++ tx[0] |= len & 0xfff; ++#ifdef JOHN_HWSEC ++ if(frag_hdr->frame_ctl & IEEE80211_FCTL_WEP ){ ++ tx[0] &= 0xffff7fff; ++ //group key may be different from pairwise key ++ if( frag_hdr->addr1[0]==0xff && ++ frag_hdr->addr1[0]==0xff && ++ frag_hdr->addr1[0]==0xff && ++ frag_hdr->addr1[0]==0xff && ++ frag_hdr->addr1[0]==0xff && ++ frag_hdr->addr1[0]==0xff ){ ++ if(ieee->broadcast_key_type == KEY_TYPE_CCMP) tx[7] |= 0x2;//ccmp ++ else tx[7] |= 0x1;//wep and tkip ++ } ++ else { ++ if(ieee->pairwise_key_type == KEY_TYPE_CCMP) tx[7] |= 0x2;//CCMP ++ else tx[7] |= 0x1;//WEP and TKIP ++ } ++ } ++ else ++#endif /*JOHN_HWSEC*/ ++ ++ tx[0] |= (1<<15); ++ ++ if (priv->ieee80211->current_network.capability&WLAN_CAPABILITY_SHORT_PREAMBLE){ ++ if (priv->plcp_preamble_mode==1 && rate!=0) { // short mode now, not long! ++ tx[0] |= (1<<16); ++ } // enable short preamble mode. ++ } ++ ++ if(morefrag) tx[0] |= (1<<17); ++ //printk(KERN_WARNING "rtl_rate = %d\n", rate); ++ tx[0] |= (rate << 24); //TX rate ++ frag_hdr->duration_id = Duration; ++ ++ if(NIC_8187B == priv->card_8187) { ++ if(bCTSEnable) { ++ tx[0] |= (1<<18); ++ } ++ ++ if(bRTSEnable) //rts enable ++ { ++ tx[0] |= ((ieeerate2rtlrate(priv->ieee80211->basic_rate))<<19);//RTS RATE ++ tx[0] |= (1<<23);//rts enable ++ tx[1] |= RtsDur;//RTS Duration ++ } ++ tx[3] |= (TxDescDuration<<16); //DURATION ++ if( WLAN_FC_GET_STYPE(le16_to_cpu(frag_hdr->frame_ctl)) == IEEE80211_STYPE_PROBE_RESP ) ++ tx[5] |= (1<<8);//(priv->retry_data<<8); //retry lim ; ++ else ++ tx[5] |= (11<<8);//(priv->retry_data<<8); //retry lim ; ++ ++ //frag_hdr->duration_id = Duration; ++ memcpy(tx+8,txbuf,len); ++ } else { ++ if ( (len>priv->rts) && priv->rts && priority==LOW_PRIORITY){ ++ tx[0] |= (1<<23); //enalbe RTS function ++ tx[1] |= RtsDur; //Need to edit here! ----hikaru ++ } ++ else { ++ tx[1]=0; ++ } ++ tx[0] |= (ieeerate2rtlrate(priv->ieee80211->basic_rate) << 19); /* RTS RATE - should be basic rate */ ++ ++ tx[2] = 3; // CW min ++ tx[2] |= (7<<4); //CW max ++ tx[2] |= (11<<8);//(priv->retry_data<<8); //retry lim ++ ++ // printk("%x\n%x\n",tx[0],tx[1]); ++ ++#ifdef DUMP_TX ++ int i; ++ printk("<Tx pkt>--rate %x---",rate); ++ for (i = 0; i < (len + 3); i++) ++ printk("%2x", ((u8*)tx)[i]); ++ printk("---------------\n"); ++#endif ++ memcpy(tx+3,txbuf,len); ++ } ++ ++#ifdef JOHN_DUMP_TXDESC ++ int i; ++ printk("<Tx descriptor>--rate %x---",rate); ++ for (i = 0; i < 8; i++) ++ printk("%8x ", tx[i]); ++ printk("\n"); ++#endif ++#ifdef JOHN_DUMP_TXPKT ++ { ++ int j; ++ printk("\n---------------------------------------------------------------------\n"); ++ printk("<Tx packet>--rate %x--urb_len in decimal %d",rate, urb_len); ++ for (j = 32; j < (urb_len); j++){ ++ if( ( (j-32)%24 )==0 ) printk("\n"); ++ printk("%2x ", ((u8*)tx)[j]); ++ } ++ printk("\n---------------------------------------------------------------------\n"); ++ ++ } ++#endif ++ ++ if(NIC_8187 == priv->card_8187) { ++ usb_fill_bulk_urb(tx_urb,priv->udev, ++ usb_sndbulkpipe(priv->udev,priority), tx, ++ urb_len, (priority == LOW_PRIORITY)?rtl8187_lptx_isr:rtl8187_nptx_isr, dev); ++ ++ } else { ++ //printk(KERN_WARNING "Tx packet use by submit urb!\n"); ++ /* FIXME check what EP is for low/norm PRI */ ++ usb_fill_bulk_urb(tx_urb,priv->udev, ++ usb_sndbulkpipe(priv->udev,priority), tx, ++ urb_len, TXISR_SELECT(priority), dev); ++ } ++ ++#if LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0) ++ status = usb_submit_urb(tx_urb, GFP_ATOMIC); ++#else ++ status = usb_submit_urb(tx_urb); ++#endif ++ ++ if (!status){ ++ //atomic_inc((priority == NORM_PRIORITY)? &priv->tx_np_pending : &priv->tx_lp_pending); ++ atomic_inc(&priv->tx_pending[priority]); ++ dev->trans_start = jiffies; ++ //printk("=====> tx_pending[%d]=%d\n", priority, atomic_read(&priv->tx_pending[priority])); ++ return 0; ++ }else{ ++ DMESGE("Error TX URB %d, error pending %d", ++ //atomic_read((priority == NORM_PRIORITY)? &priv->tx_np_pending : &priv->tx_lp_pending), ++ atomic_read(&priv->tx_pending[priority]), ++ status); ++ return -1; ++ } ++} ++ ++ short rtl8187_usb_initendpoints(struct net_device *dev) ++{ ++ struct r8180_priv *priv = ieee80211_priv(dev); ++ ++ priv->rx_urb = (struct urb**) kmalloc (sizeof(struct urb*) * (MAX_RX_URB+1), GFP_KERNEL); ++ ++ memset(priv->rx_urb, 0, sizeof(struct urb*) * MAX_RX_URB); ++ ++#ifdef JACKSON_NEW_RX ++ priv->pp_rxskb = (struct sk_buff **)kmalloc(sizeof(struct sk_buff *) * MAX_RX_URB, GFP_KERNEL); ++ if (priv->pp_rxskb == NULL) ++ goto destroy; ++ ++ memset(priv->pp_rxskb, 0, sizeof(struct sk_buff*) * MAX_RX_URB); ++#endif ++#ifdef THOMAS_BEACON ++ { ++ int align; ++ unsigned long oldaddr,newaddr; //lzm mod for 64bit cpu crash 20081107 ++ priv->rx_urb[MAX_RX_URB] = usb_alloc_urb(0, GFP_KERNEL); ++ priv->oldaddr = kmalloc(16, GFP_KERNEL); ++ oldaddr = (unsigned long)priv->oldaddr; ++ align = oldaddr&3; ++ if(align != 0 ){ ++ newaddr = oldaddr + 4 - align; ++ priv->rx_urb[MAX_RX_URB]->transfer_buffer_length = 16-4+align; ++ } ++ else{ ++ newaddr = oldaddr; ++ priv->rx_urb[MAX_RX_URB]->transfer_buffer_length = 16; ++ } ++ priv->rx_urb[MAX_RX_URB]->transfer_buffer = (u32*)newaddr; ++ } ++#endif ++ ++ ++ goto _middle; ++ ++ ++destroy: ++ ++#ifdef JACKSON_NEW_RX ++ if (priv->pp_rxskb) { ++ kfree(priv->pp_rxskb); ++ priv->pp_rxskb = NULL; ++ ++ } ++#endif ++ if (priv->rx_urb) { ++ kfree(priv->rx_urb); ++ } ++ priv->rx_urb = NULL; ++ ++ DMESGE("Endpoint Alloc Failure"); ++ return -ENOMEM; ++ ++ ++_middle: ++ ++ return 0; ++ ++} ++#ifdef THOMAS_BEACON ++void rtl8187_usb_deleteendpoints(struct net_device *dev) ++{ ++ int i; ++ struct r8180_priv *priv = ieee80211_priv(dev); ++ ++ if( in_interrupt() ) ++ printk(KERN_ALERT " %ld in interrupt \n",in_interrupt() ); ++ if(priv->rx_urb){ ++ for(i=0;i<(MAX_RX_URB+1);i++){ ++ if(priv->rx_urb[i]) { ++ usb_kill_urb(priv->rx_urb[i]); ++ usb_free_urb(priv->rx_urb[i]); ++ } ++ } ++ kfree(priv->rx_urb); ++ priv->rx_urb = NULL; ++ } ++ if(priv->oldaddr){ ++ kfree(priv->oldaddr); ++ priv->oldaddr = NULL; ++ } ++ if (priv->pp_rxskb) { ++ kfree(priv->pp_rxskb); ++ priv->pp_rxskb = 0; ++ } ++} ++#endif ++ ++void rtl8187_set_rate(struct net_device *dev) ++{ ++ int i; ++ u16 word; ++ int basic_rate,min_rr_rate,max_rr_rate; ++ ++ //if (ieee80211_is_54g(priv->ieee80211->current_network) && ++ // priv->ieee80211->state == IEEE80211_LINKED){ ++ basic_rate = ieeerate2rtlrate(240); ++ min_rr_rate = ieeerate2rtlrate(60); ++ max_rr_rate = ieeerate2rtlrate(240); ++ ++ /* ++ }else{ ++ basic_rate = ieeerate2rtlrate(20); ++ min_rr_rate = ieeerate2rtlrate(10); ++ max_rr_rate = ieeerate2rtlrate(110); ++ } ++ */ ++ ++ write_nic_byte(dev, RESP_RATE, ++ max_rr_rate<<MAX_RESP_RATE_SHIFT| min_rr_rate<<MIN_RESP_RATE_SHIFT); ++ ++ //word = read_nic_word(dev, BRSR); ++ word = read_nic_word(dev, BRSR_8187); ++ word &= ~BRSR_MBR_8185; ++ ++ ++ for(i=0;i<=basic_rate;i++) ++ word |= (1<<i); ++ ++ //write_nic_word(dev, BRSR, word); ++ write_nic_word(dev, BRSR_8187, word); ++} ++ ++ ++void rtl8187_link_change(struct net_device *dev) ++{ ++ struct r8180_priv *priv = ieee80211_priv(dev); ++ //write_nic_word(dev, BintrItv, net->beacon_interval); ++ rtl8187_net_update(dev); ++ /*update timing params*/ ++ rtl8180_set_chan(dev, priv->chan); ++ rtl8187_set_rxconf(dev); ++} ++ ++#if LINUX_VERSION_CODE >=KERNEL_VERSION(2,6,20) ++void rtl8180_wmm_param_update(struct work_struct* work) ++{ ++ struct ieee80211_device * ieee = container_of(work, struct ieee80211_device,wmm_param_update_wq); ++ struct net_device *dev = ieee->dev; ++ struct r8180_priv *priv = ieee80211_priv(dev); ++#else ++void rtl8180_wmm_param_update(struct ieee80211_device *ieee) ++{ ++ struct net_device *dev = ieee->dev; ++ struct r8180_priv *priv = ieee80211_priv(dev); ++#endif ++ u8 *ac_param = (u8 *)(ieee->current_network.wmm_param); ++ u8 mode = ieee->current_network.mode; ++ AC_CODING eACI; ++ AC_PARAM AcParam; ++ PAC_PARAM pAcParam; ++ u8 i; ++ ++ //8187 need not to update wmm param, added by David, 2006.9.8 ++ if(NIC_8187 == priv->card_8187) { ++ return; ++ } ++ ++ if(!ieee->current_network.QoS_Enable) ++ { ++ //legacy ac_xx_param update ++ ++ AcParam.longData = 0; ++ AcParam.f.AciAifsn.f.AIFSN = 2; // Follow 802.11 DIFS. ++ AcParam.f.AciAifsn.f.ACM = 0; ++ AcParam.f.Ecw.f.ECWmin = 3; // Follow 802.11 CWmin. ++ AcParam.f.Ecw.f.ECWmax = 7; // Follow 802.11 CWmax. ++ AcParam.f.TXOPLimit = 0; ++ for(eACI = 0; eACI < AC_MAX; eACI++) ++ { ++ AcParam.f.AciAifsn.f.ACI = (u8)eACI; ++ { ++ u8 u1bAIFS; ++ u32 u4bAcParam; ++ ++ ++ pAcParam = (PAC_PARAM)(&AcParam); ++ // Retrive paramters to udpate. ++ u1bAIFS = pAcParam->f.AciAifsn.f.AIFSN *(((mode&IEEE_G) == IEEE_G)?9:20) + aSifsTime; ++ u4bAcParam = ((((u32)(pAcParam->f.TXOPLimit)) << AC_PARAM_TXOP_LIMIT_OFFSET) | ++ (((u32)(pAcParam->f.Ecw.f.ECWmax)) << AC_PARAM_ECW_MAX_OFFSET) | ++ (((u32)(pAcParam->f.Ecw.f.ECWmin)) << AC_PARAM_ECW_MIN_OFFSET) | ++ (((u32)u1bAIFS) << AC_PARAM_AIFS_OFFSET)); ++ ++ switch(eACI) ++ { ++ case AC1_BK: ++ write_nic_dword(dev, AC_BK_PARAM, u4bAcParam); ++ break; ++ ++ case AC0_BE: ++ write_nic_dword(dev, AC_BE_PARAM, u4bAcParam); ++ break; ++ ++ case AC2_VI: ++ write_nic_dword(dev, AC_VI_PARAM, u4bAcParam); ++ break; ++ ++ case AC3_VO: ++ write_nic_dword(dev, AC_VO_PARAM, u4bAcParam); ++ break; ++ ++ default: ++ printk(KERN_WARNING "SetHwReg8185(): invalid ACI: %d !\n", eACI); ++ break; ++ } ++ } ++ } ++ ++ return; ++ } ++ // ++ for(i = 0; i < AC_MAX; i++){ ++ pAcParam = (AC_PARAM * )ac_param; ++ { ++ AC_CODING eACI; ++ u8 u1bAIFS; ++ u32 u4bAcParam; ++ ++ // Retrive paramters to udpate. ++ eACI = pAcParam->f.AciAifsn.f.ACI; ++ //Mode G/A: slotTimeTimer = 9; Mode B: 20 ++ u1bAIFS = pAcParam->f.AciAifsn.f.AIFSN * (((mode&IEEE_G) == IEEE_G)?9:20) + aSifsTime; ++ u4bAcParam = ((((u32)(pAcParam->f.TXOPLimit)) << AC_PARAM_TXOP_LIMIT_OFFSET) | ++ (((u32)(pAcParam->f.Ecw.f.ECWmax)) << AC_PARAM_ECW_MAX_OFFSET) | ++ (((u32)(pAcParam->f.Ecw.f.ECWmin)) << AC_PARAM_ECW_MIN_OFFSET) | ++ (((u32)u1bAIFS) << AC_PARAM_AIFS_OFFSET)); ++ ++ switch(eACI) ++ { ++ case AC1_BK: ++ write_nic_dword(dev, AC_BK_PARAM, u4bAcParam); ++ //printk(KERN_WARNING "[%04x]:0x%08x\n",AC_BK_PARAM,read_nic_dword(dev, AC_BK_PARAM)); ++ break; ++ ++ case AC0_BE: ++ write_nic_dword(dev, AC_BE_PARAM, u4bAcParam); ++ //printk(KERN_WARNING "[%04x]:0x%08x\n",AC_BE_PARAM,read_nic_dword(dev, AC_BE_PARAM)); ++ break; ++ ++ case AC2_VI: ++ write_nic_dword(dev, AC_VI_PARAM, u4bAcParam); ++ //printk(KERN_WARNING "[%04x]:0x%08x\n",AC_VI_PARAM,read_nic_dword(dev, AC_VI_PARAM)); ++ break; ++ ++ case AC3_VO: ++ write_nic_dword(dev, AC_VO_PARAM, u4bAcParam); ++ //printk(KERN_WARNING "[%04x]:0x%08x\n",AC_VO_PARAM,read_nic_dword(dev, AC_VO_PARAM)); ++ break; ++ ++ default: ++ printk(KERN_WARNING "SetHwReg8185(): invalid ACI: %d !\n", eACI); ++ break; ++ } ++ } ++ ac_param += (sizeof(AC_PARAM)); ++ } ++} ++ ++int IncludedInSupportedRates(struct r8180_priv *priv, u8 TxRate ) ++{ ++ u8 rate_len; ++ u8 rate_ex_len; ++ u8 RateMask = 0x7F; ++ u8 idx; ++ unsigned short Found = 0; ++ u8 NaiveTxRate = TxRate&RateMask; ++ ++ rate_len = priv->ieee80211->current_network.rates_len; ++ rate_ex_len = priv->ieee80211->current_network.rates_ex_len; ++ ++ for( idx=0; idx< rate_len; idx++ ){ ++ if( (priv->ieee80211->current_network.rates[idx] & RateMask) == NaiveTxRate ) { ++ Found = 1; ++ goto found_rate; ++ } ++ } ++ ++ for( idx=0; idx< rate_ex_len; idx++ ) { ++ if( (priv->ieee80211->current_network.rates_ex[idx] & RateMask) == NaiveTxRate ) { ++ Found = 1; ++ goto found_rate; ++ } ++ } ++ ++ return Found; ++ found_rate: ++ return Found; ++} ++// ++// Description: ++// Get the Tx rate one degree up form the input rate in the supported rates. ++// Return the upgrade rate if it is successed, otherwise return the input rate. ++// By Bruce, 2007-06-05. ++// ++u8 GetUpgradeTxRate(struct net_device *dev, u8 rate) ++{ ++ struct r8180_priv *priv = ieee80211_priv(dev); ++ u8 UpRate; ++ ++ // Upgrade 1 degree. ++ switch(rate) ++ { ++ case 108: // Up to 54Mbps. ++ UpRate = 108; ++ break; ++ ++ case 96: // Up to 54Mbps. ++ UpRate = 108; ++ break; ++ ++ case 72: // Up to 48Mbps. ++ UpRate = 96; ++ break; ++ ++ case 48: // Up to 36Mbps. ++ UpRate = 72; ++ break; ++ ++ case 36: // Up to 24Mbps. ++ UpRate = 48; ++ break; ++ ++ case 22: // Up to 18Mbps. ++ UpRate = 36; ++ break; ++ ++ case 11: // Up to 11Mbps. ++ UpRate = 22; ++ break; ++ ++ case 4: // Up to 5.5Mbps. ++ UpRate = 11; ++ break; ++ ++ case 2: // Up to 2Mbps. ++ UpRate = 4; ++ break; ++ ++ default: ++ printk("GetUpgradeTxRate(): Input Tx Rate(%d) is undefined!\n", rate); ++ return rate; ++ } ++ // Check if the rate is valid. ++ if(IncludedInSupportedRates(priv, UpRate)) ++ { ++// printk("GetUpgradeTxRate(): GetUpgrade Tx rate(%d) from %d !\n", UpRate, priv->CurrentOperaRate); ++ return UpRate; ++ } ++ else ++ { ++ printk("GetUpgradeTxRate(): Tx rate (%d) is not in supported rates\n", UpRate); ++ return rate; ++ } ++ return rate; ++} ++// ++// Description: ++// Get the Tx rate one degree down form the input rate in the supported rates. ++// Return the degrade rate if it is successed, otherwise return the input rate. ++// By Bruce, 2007-06-05. ++// ++u8 GetDegradeTxRate( struct net_device *dev, u8 rate) ++{ ++ struct r8180_priv *priv = ieee80211_priv(dev); ++ u8 DownRate; ++ ++ // Upgrade 1 degree. ++ switch(rate) ++ { ++ case 108: // Down to 48Mbps. ++ DownRate = 96; ++ break; ++ ++ case 96: // Down to 36Mbps. ++ DownRate = 72; ++ break; ++ ++ case 72: // Down to 24Mbps. ++ DownRate = 48; ++ break; ++ ++ case 48: // Down to 18Mbps. ++ DownRate = 36; ++ break; ++ ++ case 36: // Down to 11Mbps. ++ DownRate = 22; ++ break; ++ ++ case 22: // Down to 5.5Mbps. ++ DownRate = 11; ++ break; ++ ++ case 11: // Down to 2Mbps. ++ DownRate = 4; ++ break; ++ ++ case 4: // Down to 1Mbps. ++ DownRate = 2; ++ break; ++ ++ case 2: // Down to 1Mbps. ++ DownRate = 2; ++ break; ++ ++ default: ++ printk("GetDegradeTxRate(): Input Tx Rate(%d) is undefined!\n", rate); ++ return rate; ++ } ++ // Check if the rate is valid. ++ if(IncludedInSupportedRates(priv, DownRate)){ ++// printk("GetDegradeTxRate(): GetDegrade Tx rate(%d) from %d!\n", DownRate, priv->CurrentOperaRate); ++ return DownRate; ++ }else{ ++ printk("GetDegradeTxRate(): Tx rate (%d) is not in supported rates\n", DownRate); ++ return rate; ++ } ++ return rate; ++} ++ ++// ++// Helper function to determine if specified data rate is ++// CCK rate. ++// 2005.01.25, by rcnjko. ++// ++bool MgntIsCckRate(u16 rate ) ++{ ++ bool bReturn = false; ++ ++ if((rate <= 22) && (rate != 12) && (rate != 18)){ ++ bReturn = true; ++ } ++ ++ return bReturn; ++} ++//by amy for rate adaptive ++// ++// Description: ++// Core logic to adjust Tx data rate in STA mode according to ++// OFDM retry count ratio. ++// ++// Note: ++// RTL8187 : pHalData->CurrRetryCnt = TallyCnt ++// RTL8187B : pHalData->CurrRetryCnt = PktRetryCnt in TxClosedCommand ++// ++void sta_rateadaptive8187B(struct net_device *dev) ++{ ++ struct r8180_priv *priv = ieee80211_priv(dev); ++ unsigned long CurrTxokCnt; ++ u16 CurrRetryCnt; ++ u16 CurrRetryRate; ++ unsigned long CurrRxokCnt; ++ bool bTryUp = false; ++ bool bTryDown = false; ++ u8 TryUpTh = 1; ++ u8 TryDownTh = 2; ++ u32 TxThroughput; ++ long CurrSignalStrength; ++ bool bUpdateInitialGain = false; ++ CurrRetryCnt = priv->CurrRetryCnt; ++ CurrTxokCnt = (priv->stats.txbeaconokint + priv->stats.txmanageokint + ++ priv->stats.txvookint + priv->stats.txviokint + priv->stats.txbeokint)- priv->LastTxokCnt; ++ CurrRxokCnt = priv->stats.rxok - priv->LastRxokCnt; ++ CurrSignalStrength = priv->RecvSignalPower; ++ TxThroughput = (u32)(priv->txokbytestotal - priv->LastTxOKBytes); ++ priv->LastTxOKBytes = priv->txokbytestotal; ++ priv->CurrentOperaRate = priv->ieee80211->rate / 5; ++ //printk("priv->CurrentOperaRate is %d\n",priv->CurrentOperaRate); ++ ++#if 1 ++ //2 Compute retry ratio. ++ if (CurrTxokCnt>0) ++ { ++ CurrRetryRate = (u16)(CurrRetryCnt*100/CurrTxokCnt); ++ } ++ else ++ { // It may be serious retry. To distinguish serious retry or no packets modified by Bruce ++ CurrRetryRate = (u16)(CurrRetryCnt*100/1); ++ } ++#endif ++ ++ ++ //printk("\n(1) priv->LastRetryRate: %d \n",priv->LastRetryRate); ++ //printk("(2) CurrRetryCnt = %d \n", CurrRetryCnt); ++ //printk("(3) TxokCnt = %d \n", CurrTxokCnt); ++ //printk("(4) CurrRetryRate = %d \n", CurrRetryRate); ++ //printk("(5) SignalStrength = %d \n",priv->RecvSignalPower); ++ ++ priv->LastRetryCnt = priv->CurrRetryCnt; ++ priv->LastTxokCnt = (priv->stats.txbeaconokint + priv->stats.txmanageokint + ++ priv->stats.txvookint + priv->stats.txviokint + priv->stats.txbeokint); ++ priv->LastRxokCnt = priv->stats.rxok; ++ priv->CurrRetryCnt = 0; ++ //2No Tx packets, return to init_rate or not? ++ if (CurrRetryRate==0 && CurrTxokCnt == 0) ++ { ++ // ++ // 2007.04.09, by Roger. after 4.5 seconds in this condition, we try to raise rate. ++ // ++ priv->TryupingCountNoData++; ++ ++ //printk("No Tx packets, TryupingCountNoData(%d)\n", priv->TryupingCountNoData); ++ //printk("(6) priv->CurrentOperaRate =%d\n", priv->CurrentOperaRate); ++ ++ if (priv->TryupingCountNoData>15) ++ { ++ priv->TryupingCountNoData = 0; ++ priv->CurrentOperaRate = GetUpgradeTxRate(dev, priv->CurrentOperaRate); ++ // Reset Fail Record ++ priv->LastFailTxRate = 0; ++ priv->LastFailTxRateSS = -200; ++ priv->FailTxRateCount = 0; ++ } ++ goto SetInitialGain; ++ } ++ else ++ { ++ priv->TryupingCountNoData=0; //Reset trying up times. ++ } ++ ++ // ++ // For Netgear case, I comment out the following signal strength estimation, ++ // which can results in lower rate to transmit when sample is NOT enough (e.g. PING request). ++ // 2007.04.09, by Roger. ++ // ++#if 1 ++ // If sample is not enough, we use signalstrength. ++ if ( CurrTxokCnt<10|| CurrRetryCnt<10) ++ { ++ //printk("Sample is not enough, we use signalstrength for rate adaptive\n"); ++ //After 3 sec, and trying up. ++ priv->TryupingCountNoData++; ++ if (priv->TryupingCountNoData>10) ++ { ++ //printk("Sample is not enough and After 3 sec try up\n"); ++ priv->TryupingCountNoData=0; ++ ++ // ++ // Added by Roger, 2007.01.04. ++ // Signal strength plus 3 for air link. ++ // ++ ++ if ( CurrSignalStrength>-68 )//&& IncludedInSupportedRates(Adapter, 108) ) ++ { ++ priv->ieee80211->rate = 540; ++ //pMgntInfo->CurrentOperaRate = 108; ++ } ++ else if (CurrSignalStrength>-70)// && IncludedInSupportedRates(Adapter, 96) ) ++ { ++ priv->ieee80211->rate = 480; ++ //pMgntInfo->CurrentOperaRate = 96; ++ } ++ else if (CurrSignalStrength>-73)// && IncludedInSupportedRates(Adapter, 72) ) ++ { ++ priv->ieee80211->rate = 360; ++ //pMgntInfo->CurrentOperaRate = 72; ++ } ++ else if (CurrSignalStrength>-79)// && IncludedInSupportedRates(Adapter, 48) ) ++ { ++ priv->ieee80211->rate = 240; ++ //pMgntInfo->CurrentOperaRate = 48; ++ } ++ else if (CurrSignalStrength>-81)// && IncludedInSupportedRates(Adapter, 36) ) ++ { ++ priv->ieee80211->rate = 180; ++ //pMgntInfo->CurrentOperaRate = 36; ++ } ++ else if (CurrSignalStrength>-83)// && IncludedInSupportedRates(Adapter, 22) ) ++ { ++ priv->ieee80211->rate = 110; ++ //pMgntInfo->CurrentOperaRate = 22; ++ } ++ else if (CurrSignalStrength>-85)// && IncludedInSupportedRates(Adapter, 11) ) ++ { ++ priv->ieee80211->rate = 55; ++ //pMgntInfo->CurrentOperaRate = 11; ++ } ++ else if (CurrSignalStrength>-89)// && IncludedInSupportedRates(Adapter, 4) ) ++ { ++ priv->ieee80211->rate = 20; ++ //pMgntInfo->CurrentOperaRate = 4; ++ } ++ ++ ++ } ++ ++ //2004.12.23 skip record for 0 ++ //pHalData->LastRetryRate = CurrRetryRate; ++ //printk("pMgntInfo->CurrentOperaRate =%d\n",priv->ieee80211->rate); ++ return; ++ } ++ else ++ { ++ priv->TryupingCountNoData=0; ++ } ++#endif ++ // ++ // Restructure rate adaptive as the following main stages: ++ // (1) Add retry threshold in 54M upgrading condition with signal strength. ++ // (2) Add the mechanism to degrade to CCK rate according to signal strength ++ // and retry rate. ++ // (3) Remove all Initial Gain Updates over OFDM rate. To avoid the complicated ++ // situation, Initial Gain Update is upon on DIG mechanism except CCK rate. ++ // (4) Add the mehanism of trying to upgrade tx rate. ++ // (5) Record the information of upping tx rate to avoid trying upping tx rate constantly. ++ // By Bruce, 2007-06-05. ++ // ++ // ++ ++ // 11Mbps or 36Mbps ++ // Check more times in these rate(key rates). ++ // ++ if(priv->CurrentOperaRate == 22 || priv->CurrentOperaRate == 72) ++ { ++ TryUpTh += 9; ++ } ++ // ++ // Let these rates down more difficult. ++ // ++ if(MgntIsCckRate(priv->CurrentOperaRate) || priv->CurrentOperaRate == 36) ++ { ++ TryDownTh += 1; ++ } ++ ++ //1 Adjust Rate. ++ if (priv->bTryuping == true) ++ { ++ //2 For Test Upgrading mechanism ++ // Note: ++ // Sometimes the throughput is upon on the capability bwtween the AP and NIC, ++ // thus the low data rate does not improve the performance. ++ // We randomly upgrade the data rate and check if the retry rate is improved. ++ ++ // Upgrading rate did not improve the retry rate, fallback to the original rate. ++ if ( (CurrRetryRate > 25) && TxThroughput < priv->LastTxThroughput) ++ { ++ //Not necessary raising rate, fall back rate. ++ bTryDown = true; ++ //printk("Not necessary raising rate, fall back rate....\n"); ++ //printk("(7) priv->CurrentOperaRate =%d, TxThroughput = %d, LastThroughput = %d\n", ++ // priv->CurrentOperaRate, TxThroughput, priv->LastTxThroughput); ++ } ++ else ++ { ++ priv->bTryuping = false; ++ } ++ } ++ else if (CurrSignalStrength > -51 && (CurrRetryRate < 100)) ++ { ++ //2For High Power ++ // ++ // Added by Roger, 2007.04.09. ++ // Return to highest data rate, if signal strength is good enough. ++ // SignalStrength threshold(-50dbm) is for RTL8186. ++ // Revise SignalStrength threshold to -51dbm. ++ // ++ // Also need to check retry rate for safety, by Bruce, 2007-06-05. ++ if(priv->CurrentOperaRate != 108) ++ { ++ bTryUp = true; ++ // Upgrade Tx Rate directly. ++ priv->TryupingCount += TryUpTh; ++ //printk("StaRateAdaptive87B: Power(%d) is high enough!!. \n", CurrSignalStrength); ++ } ++ } ++ // To avoid unstable rate jumping, comment out this condition, by Bruce, 2007-06-26. ++ /* ++ else if(CurrSignalStrength < -86 && CurrRetryRate >= 100) ++ { ++ //2 For Low Power ++ // ++ // Low signal strength and high current tx rate may cause Tx rate to degrade too slowly. ++ // Update Tx rate to CCK rate directly. ++ // By Bruce, 2007-06-05. ++ // ++ if(!MgntIsCckRate(pMgntInfo->CurrentOperaRate)) ++ { ++ if(CurrSignalStrength > -88 && IncludedInSupportedRates(Adapter, 22)) // 11M ++ pMgntInfo->CurrentOperaRate = 22; ++ else if(CurrSignalStrength > -90 && IncludedInSupportedRates(Adapter, 11)) // 5.5M ++ pMgntInfo->CurrentOperaRate = 11; ++ else if(CurrSignalStrength > -92 && IncludedInSupportedRates(Adapter, 4)) // 2M ++ pMgntInfo->CurrentOperaRate = 4; ++ else // 1M ++ pMgntInfo->CurrentOperaRate = 2; ++ } ++ else if(CurrRetryRate >= 200) ++ { ++ pMgntInfo->CurrentOperaRate = GetDegradeTxRate(Adapter, pMgntInfo->CurrentOperaRate); ++ } ++ RT_TRACE(COMP_RATE, DBG_LOUD, ("RA: Low Power(%d), or High Retry Rate(%d), set rate to CCK rate (%d). \n", ++ CurrSignalStrength, CurrRetryRate, pMgntInfo->CurrentOperaRate)); ++ bUpdateInitialGain = TRUE; ++ // Reset Fail Record ++ pHalData->LastFailTxRate = 0; ++ pHalData->LastFailTxRateSS = -200; ++ pHalData->FailTxRateCount = 0; ++ goto SetInitialGain; ++ } ++ */ ++ else if(CurrTxokCnt< 100 && CurrRetryRate >= 600) ++ { ++ //2 For Serious Retry ++ // ++ // Traffic is not busy but our Tx retry is serious. ++ // ++ bTryDown = true; ++ // Let Rate Mechanism to degrade tx rate directly. ++ priv->TryDownCountLowData += TryDownTh; ++ //printk("RA: Tx Retry is serious. Degrade Tx Rate to %d directly...\n", priv->CurrentOperaRate); ++ } ++ else if ( priv->CurrentOperaRate == 108 ) ++ { ++ //2For 54Mbps ++ // if ( (CurrRetryRate>38)&&(pHalData->LastRetryRate>35)) ++ if ( (CurrRetryRate>33)&&(priv->LastRetryRate>32)) ++ { ++ //(30,25) for cable link threshold. (38,35) for air link. ++ //Down to rate 48Mbps. ++ bTryDown = true; ++ } ++ } ++ else if ( priv->CurrentOperaRate == 96 ) ++ { ++ //2For 48Mbps ++ // if ( ((CurrRetryRate>73) && (pHalData->LastRetryRate>72)) && IncludedInSupportedRates(Adapter, 72) ) ++ if ( ((CurrRetryRate>48) && (priv->LastRetryRate>47))) ++ { ++ //(73, 72) for temp used. ++ //(25, 23) for cable link, (60,59) for air link. ++ //CurrRetryRate plus 25 and 26 respectively for air link. ++ //Down to rate 36Mbps. ++ bTryDown = true; ++ } ++ else if ( (CurrRetryRate<8) && (priv->LastRetryRate<8) ) //TO DO: need to consider (RSSI) ++ { ++ bTryUp = true; ++ } ++ } ++ else if ( priv->CurrentOperaRate == 72 ) ++ { ++ //2For 36Mbps ++ //if ( (CurrRetryRate>97) && (pHalData->LastRetryRate>97)) ++ if ( (CurrRetryRate>55) && (priv->LastRetryRate>54)) ++ { ++ //(30,25) for cable link threshold respectively. (103,10) for air link respectively. ++ //CurrRetryRate plus 65 and 69 respectively for air link threshold. ++ //Down to rate 24Mbps. ++ bTryDown = true; ++ } ++ // else if ( (CurrRetryRate<20) && (pHalData->LastRetryRate<20) && IncludedInSupportedRates(Adapter, 96) )//&& (device->LastRetryRate<15) ) //TO DO: need to consider (RSSI) ++ else if ( (CurrRetryRate<15) && (priv->LastRetryRate<16))//&& (device->LastRetryRate<15) ) //TO DO: need to consider (RSSI) ++ { ++ bTryUp = true; ++ } ++ } ++ else if ( priv->CurrentOperaRate == 48 ) ++ { ++ //2For 24Mbps ++ // if ( ((CurrRetryRate>119) && (pHalData->LastRetryRate>119) && IncludedInSupportedRates(Adapter, 36))) ++ if ( ((CurrRetryRate>63) && (priv->LastRetryRate>62))) ++ { ++ //(15,15) for cable link threshold respectively. (119, 119) for air link threshold. ++ //Plus 84 for air link threshold. ++ //Down to rate 18Mbps. ++ bTryDown = true; ++ } ++ // else if ( (CurrRetryRate<14) && (pHalData->LastRetryRate<15) && IncludedInSupportedRates(Adapter, 72)) //TO DO: need to consider (RSSI) ++ else if ( (CurrRetryRate<20) && (priv->LastRetryRate<21)) //TO DO: need to consider (RSSI) ++ { ++ bTryUp = true; ++ } ++ } ++ else if ( priv->CurrentOperaRate == 36 ) ++ { ++ //2For 18Mbps ++ if ( ((CurrRetryRate>109) && (priv->LastRetryRate>109))) ++ { ++ //(99,99) for cable link, (109,109) for air link. ++ //Down to rate 11Mbps. ++ bTryDown = true; ++ } ++ // else if ( (CurrRetryRate<15) && (pHalData->LastRetryRate<16) && IncludedInSupportedRates(Adapter, 48)) //TO DO: need to consider (RSSI) ++ else if ( (CurrRetryRate<25) && (priv->LastRetryRate<26)) //TO DO: need to consider (RSSI) ++ { ++ bTryUp = true; ++ } ++ } ++ else if ( priv->CurrentOperaRate == 22 ) ++ { ++ //2For 11Mbps ++ // if (CurrRetryRate>299 && IncludedInSupportedRates(Adapter, 11)) ++ if (CurrRetryRate>95) ++ { ++ bTryDown = true; ++ } ++ else if (CurrRetryRate<55)//&& (device->LastRetryRate<55) ) //TO DO: need to consider (RSSI) ++ { ++ bTryUp = true; ++ } ++ } ++ else if ( priv->CurrentOperaRate == 11 ) ++ { ++ //2For 5.5Mbps ++ // if (CurrRetryRate>159 && IncludedInSupportedRates(Adapter, 4) ) ++ if (CurrRetryRate>149) ++ { ++ bTryDown = true; ++ } ++ // else if ( (CurrRetryRate<30) && (pHalData->LastRetryRate<30) && IncludedInSupportedRates(Adapter, 22) ) ++ else if ( (CurrRetryRate<60) && (priv->LastRetryRate < 65)) ++ { ++ bTryUp = true; ++ } ++ } ++ else if ( priv->CurrentOperaRate == 4 ) ++ { ++ //2For 2 Mbps ++ if((CurrRetryRate>99) && (priv->LastRetryRate>99)) ++ { ++ bTryDown = true; ++ } ++ // else if ( (CurrRetryRate<50) && (pHalData->LastRetryRate<65) && IncludedInSupportedRates(Adapter, 11) ) ++ else if ( (CurrRetryRate < 65) && (priv->LastRetryRate < 70)) ++ { ++ bTryUp = true; ++ } ++ } ++ else if ( priv->CurrentOperaRate == 2 ) ++ { ++ //2For 1 Mbps ++ // if ( (CurrRetryRate<50) && (pHalData->LastRetryRate<65) && IncludedInSupportedRates(Adapter, 4)) ++ if ( (CurrRetryRate<70) && (priv->LastRetryRate<75)) ++ { ++ bTryUp = true; ++ } ++ } ++ if(bTryUp && bTryDown) ++ printk("StaRateAdaptive87B(): Tx Rate tried upping and downing simultaneously!\n"); ++ ++ //1 Test Upgrading Tx Rate ++ // Sometimes the cause of the low throughput (high retry rate) is the compatibility between the AP and NIC. ++ // To test if the upper rate may cause lower retry rate, this mechanism randomly occurs to test upgrading tx rate. ++ if(!bTryUp && !bTryDown && (priv->TryupingCount == 0) && (priv->TryDownCountLowData == 0) ++ && priv->CurrentOperaRate != 108 && priv->FailTxRateCount < 2) ++ { ++#if 1 ++ if(jiffies% (CurrRetryRate + 101) == 0) ++ { ++ bTryUp = true; ++ priv->bTryuping = true; ++ printk("======================================================>StaRateAdaptive87B(): Randomly try upgrading...\n"); ++ } ++#endif ++ } ++ //1 Rate Mechanism ++ if(bTryUp) ++ { ++ priv->TryupingCount++; ++ priv->TryDownCountLowData = 0; ++ ++ // ++ // Check more times if we need to upgrade indeed. ++ // Because the largest value of pHalData->TryupingCount is 0xFFFF and ++ // the largest value of pHalData->FailTxRateCount is 0x14, ++ // this condition will be satisfied at most every 2 min. ++ // ++ if((priv->TryupingCount > (TryUpTh + priv->FailTxRateCount * priv->FailTxRateCount)) || ++ (CurrSignalStrength > priv->LastFailTxRateSS) || priv->bTryuping) ++ { ++ priv->TryupingCount = 0; ++ // ++ // When transfering from CCK to OFDM, DIG is an important issue. ++ // ++ if(priv->CurrentOperaRate == 22) ++ bUpdateInitialGain = true; ++ // (1)To avoid upgrade frequently to the fail tx rate, add the FailTxRateCount into the threshold. ++ // (2)If the signal strength is increased, it may be able to upgrade. ++ priv->CurrentOperaRate = GetUpgradeTxRate(dev, priv->CurrentOperaRate); ++ //printk("StaRateAdaptive87B(): Upgrade Tx Rate to %d\n", priv->CurrentOperaRate); ++ ++ // Update Fail Tx rate and count. ++ if(priv->LastFailTxRate != priv->CurrentOperaRate) ++ { ++ priv->LastFailTxRate = priv->CurrentOperaRate; ++ priv->FailTxRateCount = 0; ++ priv->LastFailTxRateSS = -200; // Set lowest power. ++ } ++ } ++ } ++ else ++ { ++ if(priv->TryupingCount > 0) ++ priv->TryupingCount --; ++ } ++ ++ if(bTryDown) ++ { ++ priv->TryDownCountLowData++; ++ priv->TryupingCount = 0; ++ ++ ++ //Check if Tx rate can be degraded or Test trying upgrading should fallback. ++ if(priv->TryDownCountLowData > TryDownTh || priv->bTryuping) ++ { ++ priv->TryDownCountLowData = 0; ++ priv->bTryuping = false; ++ // Update fail information. ++ if(priv->LastFailTxRate == priv->CurrentOperaRate) ++ { ++ priv->FailTxRateCount ++; ++ // Record the Tx fail rate signal strength. ++ if(CurrSignalStrength > priv->LastFailTxRateSS) ++ { ++ priv->LastFailTxRateSS = CurrSignalStrength; ++ } ++ } ++ else ++ { ++ priv->LastFailTxRate = priv->CurrentOperaRate; ++ priv->FailTxRateCount = 1; ++ priv->LastFailTxRateSS = CurrSignalStrength; ++ } ++ priv->CurrentOperaRate = GetDegradeTxRate(dev, priv->CurrentOperaRate); ++ // ++ // When it is CCK rate, it may need to update initial gain to receive lower power packets. ++ // ++ if(MgntIsCckRate(priv->CurrentOperaRate)) ++ { ++ bUpdateInitialGain = true; ++ } ++ //printk("StaRateAdaptive87B(): Degrade Tx Rate to %d\n", priv->CurrentOperaRate); ++ } ++ } ++ else ++ { ++ if(priv->TryDownCountLowData > 0) ++ priv->TryDownCountLowData --; ++ } ++ // Keep the Tx fail rate count to equal to 0x15 at most. ++ // Reduce the fail count at least to 10 sec if tx rate is tending stable. ++ if(priv->FailTxRateCount >= 0x15 || ++ (!bTryUp && !bTryDown && priv->TryDownCountLowData == 0 && priv->TryupingCount && priv->FailTxRateCount > 0x6)) ++ { ++ priv->FailTxRateCount --; ++ } ++ ++ // ++ // We need update initial gain when we set tx rate "from OFDM to CCK" or ++ // "from CCK to OFDM". ++ // ++SetInitialGain: ++#if 1 //to be done ++ if(bUpdateInitialGain) ++ { ++ if(MgntIsCckRate(priv->CurrentOperaRate)) // CCK ++ { ++ if(priv->InitialGain > priv->RegBModeGainStage) ++ { ++ if(CurrSignalStrength < -85) // Low power, OFDM [0x17] = 26. ++ { ++ priv->InitialGain = priv->RegBModeGainStage; ++ } ++ else if(priv->InitialGain > priv->RegBModeGainStage + 1) ++ { ++ priv->InitialGain -= 2; ++ } ++ else ++ { ++ priv->InitialGain --; ++ } ++ UpdateInitialGain(dev); ++ } ++ } ++ else // OFDM ++ { ++ if(priv->InitialGain < 4) ++ { ++ priv->InitialGain ++; ++ UpdateInitialGain(dev); ++ } ++ } ++ } ++#endif ++ //Record the related info ++ priv->LastRetryRate = CurrRetryRate; ++ priv->LastTxThroughput = TxThroughput; ++ priv->ieee80211->rate = priv->CurrentOperaRate * 5; ++} ++ ++#if LINUX_VERSION_CODE >=KERNEL_VERSION(2,6,20) ++void rtl8180_rate_adapter(struct work_struct * work) ++{ ++ struct delayed_work *dwork = container_of(work,struct delayed_work,work); ++ struct ieee80211_device *ieee = container_of(dwork,struct ieee80211_device,rate_adapter_wq); ++ struct net_device *dev = ieee->dev; ++#else ++void rtl8180_rate_adapter(struct net_device *dev) ++{ ++ ++#endif ++ sta_rateadaptive8187B(dev); ++} ++ ++void timer_rate_adaptive(unsigned long data) ++{ ++ struct r8180_priv* priv = ieee80211_priv((struct net_device *)data); ++ //DMESG("---->timer_rate_adaptive()\n"); ++ if(!priv->up) ++ { ++ //DMESG("<----timer_rate_adaptive():driver is not up!\n"); ++ return; ++ } ++ if( (priv->ieee80211->mode != IEEE_B) && ++ (priv->ieee80211->iw_mode != IW_MODE_MASTER) ++ && ((priv->ieee80211->state == IEEE80211_LINKED)||(priv->ieee80211->state == IEEE80211_MESH_LINKED))) ++ { ++ //DMESG("timer_rate_adaptive():schedule rate_adapter_wq\n"); ++#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,20) ++ queue_delayed_work(priv->ieee80211->wq,&priv->ieee80211->rate_adapter_wq, 0); ++#else ++ queue_work(priv->ieee80211->wq,&priv->ieee80211->rate_adapter_wq); ++#endif ++ } ++ ++ mod_timer(&priv->rateadapter_timer, jiffies + MSECS(DEFAULT_RATE_ADAPTIVE_TIMER_PERIOD)); ++ //DMESG("<----timer_rate_adaptive()\n"); ++} ++//by amy for rate adaptive ++ ++ ++void rtl8180_irq_rx_tasklet_new(struct r8180_priv *priv); ++void rtl8180_irq_rx_tasklet(struct r8180_priv *priv); ++ ++//YJ,add,080828,for KeepAlive ++#if 0 ++static void MgntLinkKeepAlive(struct r8180_priv *priv ) ++{ ++ if (priv->keepAliveLevel == 0) ++ return; ++ ++ if(priv->ieee80211->state == IEEE80211_LINKED) ++ { ++ // ++ // Keep-Alive. ++ // ++ //printk("LastTx:%d Tx:%d LastRx:%d Rx:%ld Idle:%d\n",priv->link_detect.LastNumTxUnicast,priv->NumTxUnicast, priv->link_detect.LastNumRxUnicast, priv->ieee80211->NumRxUnicast, priv->link_detect.IdleCount); ++ ++ if ( (priv->keepAliveLevel== 2) || ++ (priv->link_detect.LastNumTxUnicast == priv->NumTxUnicast && ++ priv->link_detect.LastNumRxUnicast == priv->ieee80211->NumRxUnicast ) ++ ) ++ { ++ priv->link_detect.IdleCount++; ++ ++ // ++ // Send a Keep-Alive packet packet to AP if we had been idle for a while. ++ // ++ if(priv->link_detect.IdleCount >= ((KEEP_ALIVE_INTERVAL / CHECK_FOR_HANG_PERIOD)-1) ) ++ { ++ priv->link_detect.IdleCount = 0; ++ ieee80211_sta_ps_send_null_frame(priv->ieee80211, false); ++ } ++ } ++ else ++ { ++ priv->link_detect.IdleCount = 0; ++ } ++ priv->link_detect.LastNumTxUnicast = priv->NumTxUnicast; ++ priv->link_detect.LastNumRxUnicast = priv->ieee80211->NumRxUnicast; ++ } ++} ++//YJ,add,080828,for KeepAlive,end ++#endif ++void InactivePowerSave(struct net_device *dev) ++{ ++ struct r8180_priv *priv = (struct r8180_priv *)ieee80211_priv(dev); ++ ++ // ++ // This flag "bSwRfProcessing", indicates the status of IPS procedure, should be set if the IPS workitem ++ // is really scheduled. ++ // The old code, sets this flag before scheduling the IPS workitem and however, at the same time the ++ // previous IPS workitem did not end yet, fails to schedule the current workitem. Thus, bSwRfProcessing ++ // blocks the IPS procedure of switching RF. ++ // By Bruce, 2007-12-25. ++ // ++ priv->bSwRfProcessing = true; ++ MgntActSet_RF_State(dev, priv->eInactivePowerState, RF_CHANGE_BY_IPS); ++ ++ // ++ // To solve CAM values miss in RF OFF, rewrite CAM values after RF ON. By Bruce, 2007-09-20. ++ // ++#if 0 ++ while( index < 4 ) ++ { ++ if( ( pMgntInfo->SecurityInfo.PairwiseEncAlgorithm == WEP104_Encryption ) || ++ (pMgntInfo->SecurityInfo.PairwiseEncAlgorithm == WEP40_Encryption) ) ++ { ++ if( pMgntInfo->SecurityInfo.KeyLen[index] != 0) ++ pAdapter->HalFunc.SetKeyHandler(pAdapter, index, 0, FALSE, pMgntInfo->SecurityInfo.PairwiseEncAlgorithm, TRUE, FALSE); ++ ++ } ++ index++; ++ } ++#endif ++ priv->bSwRfProcessing = false; ++} ++ ++// ++// Description: ++// Enter the inactive power save mode. RF will be off ++// 2007.08.17, by shien chang. ++// ++void IPSEnter(struct net_device *dev) ++{ ++ struct r8180_priv *priv = (struct r8180_priv *)ieee80211_priv(dev); ++ RT_RF_POWER_STATE rtState; ++ ++ if (priv->bInactivePs) ++ { ++ rtState = priv->eRFPowerState; ++ ++ // ++ // Added by Bruce, 2007-12-25. ++ // Do not enter IPS in the following conditions: ++ // (1) RF is already OFF or Sleep ++ // (2) bSwRfProcessing (indicates the IPS is still under going) ++ // (3) Connectted (only disconnected can trigger IPS) ++ // (4) IBSS (send Beacon) ++ // (5) AP mode (send Beacon) ++ // ++ if (rtState == eRfOn && !priv->bSwRfProcessing && (priv->ieee80211->iw_mode != IW_MODE_ADHOC) ++ && (priv->ieee80211->state != IEEE80211_LINKED )) ++ { ++#ifdef CONFIG_RADIO_DEBUG ++ DMESG("IPSEnter(): Turn off RF."); ++#endif ++ priv->eInactivePowerState = eRfOff; ++ InactivePowerSave(dev); ++ //SetRFPowerState(dev, priv->eInactivePowerState); ++ //MgntActSet_RF_State(dev, priv->eInactivePowerState, RF_CHANGE_BY_IPS); ++ } ++ } ++ //printk("priv->eRFPowerState is %d\n",priv->eRFPowerState); ++} ++ ++void IPSLeave(struct net_device *dev) ++{ ++ struct r8180_priv *priv = (struct r8180_priv *)ieee80211_priv(dev); ++ RT_RF_POWER_STATE rtState; ++ if (priv->bInactivePs) ++ { ++ rtState = priv->eRFPowerState; ++ if (rtState == eRfOff && (!priv->bSwRfProcessing) && priv->RfOffReason <= RF_CHANGE_BY_IPS) ++ { ++#ifdef CONFIG_RADIO_DEBUG ++ DMESG("ISLeave(): Turn on RF."); ++#endif ++ priv->eInactivePowerState = eRfOn; ++ InactivePowerSave(dev); ++ } ++ } ++// printk("priv->eRFPowerState is %d\n",priv->eRFPowerState); ++} ++//by amy for power save ++ ++//YJ,add,081230 ++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,20)) ++void IPSLeave_wq (struct work_struct *work) ++{ ++ struct ieee80211_device *ieee = container_of(work,struct ieee80211_device,ips_leave_wq); ++ struct net_device *dev = ieee->dev; ++#else ++void IPSLeave_wq(struct net_device *dev) ++{ ++#endif ++ struct r8180_priv *priv = (struct r8180_priv *)ieee80211_priv(dev); ++ down(&priv->ieee80211->ips_sem); ++ IPSLeave(dev); ++ up(&priv->ieee80211->ips_sem); ++} ++ ++void ieee80211_ips_leave(struct net_device *dev) ++{ ++ struct r8180_priv *priv = (struct r8180_priv *)ieee80211_priv(dev); ++ if(priv->bInactivePs){ ++ if(priv->eRFPowerState == eRfOff) ++ { ++ //DMESG("%s", __FUNCTION__); ++ queue_work(priv->ieee80211->wq,&priv->ieee80211->ips_leave_wq); ++ } ++ } ++} ++//YJ,add,081230,end ++ ++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,20)) ++void rtl8180_watch_dog_wq (struct work_struct *work) ++{ ++ struct delayed_work *dwork = container_of(work,struct delayed_work,work); ++ struct ieee80211_device *ieee = container_of(dwork,struct ieee80211_device,watch_dog_wq); ++ struct net_device *dev = ieee->dev; ++#else ++void rtl8180_watch_dog_wq(struct net_device *dev) ++{ ++#endif ++ struct r8180_priv *priv = ieee80211_priv(dev); ++ //bool bEnterPS = false; ++ //bool bBusyTraffic = false; ++ u32 TotalRxNum = 0; ++ u16 SlotIndex = 0, i=0; ++ //YJ,add,080828,for link state check ++ if((priv->ieee80211->state == IEEE80211_LINKED) && (priv->ieee80211->iw_mode == IW_MODE_INFRA)){ ++ SlotIndex = (priv->link_detect.SlotIndex++) % priv->link_detect.SlotNum; ++ priv->link_detect.RxFrameNum[SlotIndex] = priv->ieee80211->NumRxDataInPeriod + priv->ieee80211->NumRxBcnInPeriod; ++ for( i=0; i<priv->link_detect.SlotNum; i++ ) ++ TotalRxNum+= priv->link_detect.RxFrameNum[i]; ++#if 0 //for roaming temp del ++ if(TotalRxNum == 0){ ++ priv->ieee80211->state = IEEE80211_ASSOCIATING; ++ printk("=========>turn to another AP\n"); ++ queue_work(priv->ieee80211->wq, &priv->ieee80211->associate_procedure_wq); ++ } ++#endif ++ } ++ priv->link_detect.NumRxOkInPeriod = 0; ++ priv->link_detect.NumTxOkInPeriod = 0; ++ priv->ieee80211->NumRxDataInPeriod = 0; ++ priv->ieee80211->NumRxBcnInPeriod = 0; ++ ++#ifdef CONFIG_IPS ++ if(priv->ieee80211->actscanning == false){ ++ if((priv->ieee80211->iw_mode == IW_MODE_INFRA) && ++ (priv->ieee80211->state == IEEE80211_NOLINK) && ++ (priv->eRFPowerState == eRfOn)) ++ { ++ //printk("actscanning:%d, state:%d, eRFPowerState:%d\n", ++ // priv->ieee80211->actscanning, ++ // priv->ieee80211->state, ++ // priv->eRFPowerState); ++ ++ down(&priv->ieee80211->ips_sem); ++ IPSEnter(dev); ++ up(&priv->ieee80211->ips_sem); ++ } ++ } ++ //queue_delayed_work(priv->ieee80211->wq,&priv->ieee80211->watch_dog_wq,IEEE80211_WATCH_DOG_TIME); ++#endif ++ ++ //printk("========================>leave rtl8180_watch_dog_wq()\n"); ++} ++ ++void watch_dog_adaptive(unsigned long data) ++{ ++ struct net_device* dev = (struct net_device*)data; ++ struct r8180_priv* priv = ieee80211_priv(dev); ++ //DMESG("---->watch_dog_adaptive()\n"); ++ if(!priv->up){ ++ //DMESG("<----watch_dog_adaptive():driver is not up!\n"); ++ return; ++ } ++ // Tx and Rx High Power Mechanism. ++ if(CheckHighPower(dev)){ ++ //printk("===============================> high power!\n"); ++#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,20) ++ queue_delayed_work(priv->ieee80211->wq,&priv->ieee80211->tx_pw_wq, 0); ++#else ++ queue_work(priv->ieee80211->wq,&priv->ieee80211->tx_pw_wq); ++#endif ++ } ++ ++ // Schedule an workitem to perform DIG ++ if(CheckDig(dev) == true){ ++ ++#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,20) ++ queue_delayed_work(priv->ieee80211->wq,&priv->ieee80211->hw_dig_wq,0); ++#else ++ queue_work(priv->ieee80211->wq,&priv->ieee80211->hw_dig_wq); ++#endif ++ } ++ ++#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,20) ++ queue_delayed_work(priv->ieee80211->wq,&priv->ieee80211->watch_dog_wq,0); ++#else ++ queue_work(priv->ieee80211->wq,&priv->ieee80211->watch_dog_wq); ++#endif ++ ++ mod_timer(&priv->watch_dog_timer, jiffies + MSECS(IEEE80211_WATCH_DOG_TIME)); ++ //DMESG("<----watch_dog_adaptive()\n"); ++} ++ ++#ifdef ENABLE_DOT11D ++ ++CHANNEL_LIST Current_tbl; ++ ++static CHANNEL_LIST ChannelPlan[] = { ++ {{1,2,3,4,5,6,7,8,9,10,11,36,40,44,48,52,56,60,64},19}, //FCC ++ {{1,2,3,4,5,6,7,8,9,10,11},11}, //IC ++ {{1,2,3,4,5,6,7,8,9,10,11,12,13,36,40,44,48,52,56,60,64},21}, //ETSI ++ {{1,2,3,4,5,6,7,8,9,10,11,12,13,36,40,44,48,52,56,60,64},21}, //Spain. Change to ETSI. ++ {{1,2,3,4,5,6,7,8,9,10,11,12,13,36,40,44,48,52,56,60,64},21}, //France. Change to ETSI. ++ {{14,36,40,44,48,52,56,60,64},9}, //MKK ++ {{1,2,3,4,5,6,7,8,9,10,11,12,13,14, 36,40,44,48,52,56,60,64},22},//MKK1 ++ {{1,2,3,4,5,6,7,8,9,10,11,12,13,36,40,44,48,52,56,60,64},21}, //Israel. ++ {{1,2,3,4,5,6,7,8,9,10,11,12,13,34,38,42,46},17}, // For 11a , TELEC ++ {{1,2,3,4,5,6,7,8,9,10,11,12,13,14},14}, //For Global Domain. 1-11:active scan, 12-14 passive scan. //+YJ, 080626 ++ {{1,2,3,4,5,6,7,8,9,10,11,12,13},13} //world wide 13: ch1~ch11 active scan, ch12~13 passive //lzm add 081205 ++}; ++ ++static void rtl8180_set_channel_map(u8 channel_plan, struct ieee80211_device *ieee) ++{ ++ int i; ++ ++ //lzm add 081205 ++ ieee->MinPassiveChnlNum=MAX_CHANNEL_NUMBER+1; ++ ieee->IbssStartChnl=0; ++ ++ switch (channel_plan) ++ { ++ case COUNTRY_CODE_FCC: ++ case COUNTRY_CODE_IC: ++ case COUNTRY_CODE_ETSI: ++ case COUNTRY_CODE_SPAIN: ++ case COUNTRY_CODE_FRANCE: ++ case COUNTRY_CODE_MKK: ++ case COUNTRY_CODE_MKK1: ++ case COUNTRY_CODE_ISRAEL: ++ case COUNTRY_CODE_TELEC: ++ { ++ Dot11d_Init(ieee); ++ ieee->bGlobalDomain = false; ++ ieee->bWorldWide13 = false; ++ if (ChannelPlan[channel_plan].Len != 0){ ++ // Clear old channel map ++ memset(GET_DOT11D_INFO(ieee)->channel_map, 0, sizeof(GET_DOT11D_INFO(ieee)->channel_map)); ++ // Set new channel map ++ for (i=0;i<ChannelPlan[channel_plan].Len;i++) ++ { ++ if(ChannelPlan[channel_plan].Channel[i] <= 14) ++ GET_DOT11D_INFO(ieee)->channel_map[ChannelPlan[channel_plan].Channel[i]] = 1; ++ } ++ } ++ break; ++ } ++ case COUNTRY_CODE_GLOBAL_DOMAIN: ++ { ++ GET_DOT11D_INFO(ieee)->bEnabled = 0; ++ Dot11d_Reset(ieee); ++ ieee->bGlobalDomain = true; ++ ieee->bWorldWide13 = false; ++ ++ //lzm add 081205 ++ ieee->MinPassiveChnlNum=12; ++ ieee->IbssStartChnl= 10; ++ ++ break; ++ } ++ case COUNTRY_CODE_WORLD_WIDE_13_INDEX://lzm add 081205 ++ { ++ Dot11d_Init(ieee); ++ ieee->bGlobalDomain = false; ++ ieee->bWorldWide13 = true; ++ ++ //lzm add 081205 ++ ieee->MinPassiveChnlNum=12; ++ ieee->IbssStartChnl= 10; ++ ++ if (ChannelPlan[channel_plan].Len != 0){ ++ // Clear old channel map ++ memset(GET_DOT11D_INFO(ieee)->channel_map, 0, sizeof(GET_DOT11D_INFO(ieee)->channel_map)); ++ // Set new channel map ++ for (i=0;i<ChannelPlan[channel_plan].Len;i++) ++ { ++ if(ChannelPlan[channel_plan].Channel[i] <= 11)//ch1~ch11 active scan ++ GET_DOT11D_INFO(ieee)->channel_map[ChannelPlan[channel_plan].Channel[i]] = 1; ++ else//ch12~13 passive scan ++ GET_DOT11D_INFO(ieee)->channel_map[ChannelPlan[channel_plan].Channel[i]] = 2; ++ } ++ } ++ ++ break; ++ } ++ default: ++ { ++ Dot11d_Init(ieee); ++ ieee->bGlobalDomain = false; ++ ieee->bWorldWide13 = false; ++ memset(GET_DOT11D_INFO(ieee)->channel_map, 0, sizeof(GET_DOT11D_INFO(ieee)->channel_map)); ++ for (i=1;i<=14;i++) ++ { ++ GET_DOT11D_INFO(ieee)->channel_map[i] = 1; ++ } ++ break; ++ } ++ } ++} ++#endif ++ ++ ++static void rtl8180_link_detect_init(plink_detect_t plink_detect) ++{ ++ memset(plink_detect, 0, sizeof(link_detect_t)); ++ plink_detect->SlotNum = DEFAULT_SLOT_NUM; ++} ++ ++#ifdef SW_ANTE_DIVERSITY ++static void rtl8187_antenna_diversity_read(struct net_device *dev) ++{ ++ struct r8180_priv *priv = ieee80211_priv(dev); ++ u16 usValue; ++ ++ //2 Read CustomerID ++ usValue = eprom_read(dev, EEPROM_SW_REVD_OFFSET>>1); ++ priv->EEPROMCustomerID = (u8)( usValue & EEPROM_CID_MASK ); ++ //DMESG("EEPROM Customer ID: %02X\n", priv->EEPROMCustomerID); ++ ++ //2 Read AntennaDiversity ++ // SW Antenna Diversity. ++ if( (usValue & EEPROM_SW_AD_MASK) != EEPROM_SW_AD_ENABLE ){ ++ priv->EEPROMSwAntennaDiversity = false; ++ DMESG("EEPROM Disable SW Antenna Diversity"); ++ }else{ ++ priv->EEPROMSwAntennaDiversity = true; ++ DMESG("EEPROM Enable SW Antenna Diversity"); ++ } ++ // Default Antenna to use. ++ if( (usValue & EEPROM_DEF_ANT_MASK) != EEPROM_DEF_ANT_1 ) { ++ priv->EEPROMDefaultAntenna1 = false; ++ DMESG("EEPROM Default Main Antenna 0"); ++ }else{ ++ priv->EEPROMDefaultAntenna1 = false; ++ DMESG( "EEPROM Default Aux Antenna 1"); ++ } ++ ++ // ++ // Antenna diversity mechanism. Added by Roger, 2007.11.05. ++ // ++ if( priv->RegSwAntennaDiversityMechanism == 0 ) // Auto //set it to 0 when init ++ {// 0: default from EEPROM. ++ priv->bSwAntennaDiverity = priv->EEPROMSwAntennaDiversity; ++ }else{// 1:disable antenna diversity, 2: enable antenna diversity. ++ priv->bSwAntennaDiverity = ((priv->RegSwAntennaDiversityMechanism == 1)? false : true); ++ } ++ //DMESG("bSwAntennaDiverity = %d\n", priv->bSwAntennaDiverity); ++ ++ ++ // ++ // Default antenna settings. Added by Roger, 2007.11.05. ++ // ++ if( priv->RegDefaultAntenna == 0)//set it to 0 when init ++ { // 0: default from EEPROM. ++ priv->bDefaultAntenna1 = priv->EEPROMDefaultAntenna1; ++ }else{// 1: main, 2: aux. ++ priv->bDefaultAntenna1 = ((priv->RegDefaultAntenna== 2) ? true : false); ++ } ++ //DMESG("bDefaultAntenna1 = %d\n", priv->bDefaultAntenna1); ++ ++//by amy for antenna ++} ++#endif ++ ++short rtl8180_init(struct net_device *dev) ++{ ++ struct r8180_priv *priv = ieee80211_priv(dev); ++ int i, j; ++ u16 word; ++ //int ch; ++ //u16 version; ++ u8 hw_version; ++ //u8 config3; ++ struct usb_device *udev; ++ u16 idProduct; ++ u16 bcdDevice; ++ //u8 chan_plan_index; ++ ++ //FIXME: these constants are placed in a bad pleace. ++ ++ //priv->txbuffsize = 1024; ++ //priv->txringcount = 32; ++ //priv->rxbuffersize = 1024; ++ //priv->rxringcount = 32; ++ //priv->txbeaconcount = 3; ++ //priv->rx_skb_complete = 1; ++ //priv->txnp_pending.ispending=0; ++ /* ^^ the SKB does not containt a partial RXed packet (is empty) */ ++ ++ //memcpy(priv->stats,0,sizeof(struct Stats)); ++ ++ //priv->irq_enabled=0; ++ priv->driver_upping = 0; ++ priv->commit = 0; ++ ++ //priv->stats.rxdmafail=0; ++ priv->stats.txrdu=0; ++ //priv->stats.rxrdu=0; ++ //priv->stats.rxnolast=0; ++ //priv->stats.rxnodata=0; ++ //priv->stats.rxreset=0; ++ //priv->stats.rxwrkaround=0; ++ //priv->stats.rxnopointer=0; ++ priv->stats.txbeerr=0; ++ priv->stats.txbkerr=0; ++ priv->stats.txvierr=0; ++ priv->stats.txvoerr=0; ++ priv->stats.txmanageerr=0; ++ priv->stats.txbeaconerr=0; ++ priv->stats.txresumed=0; ++ //priv->stats.rxerr=0; ++ //priv->stats.rxoverflow=0; ++ //priv->stats.rxint=0; ++ priv->stats.txbeokint=0; ++ priv->stats.txbkokint=0; ++ priv->stats.txviokint=0; ++ priv->stats.txvookint=0; ++ priv->stats.txmanageokint=0; ++ priv->stats.txbeaconokint=0; ++ /*priv->stats.txhpokint=0; ++ priv->stats.txhperr=0;*/ ++ priv->stats.rxurberr=0; ++ priv->stats.rxstaterr=0; ++ priv->stats.txoverflow=0; ++ priv->stats.rxok=0; ++ //priv->stats.txbeaconerr=0; ++ //priv->stats.txlperr=0; ++ //priv->stats.txlpokint=0; ++//john ++ priv->stats.txnpdrop=0; ++ priv->stats.txlpdrop =0; ++ priv->stats.txbedrop =0; ++ priv->stats.txbkdrop =0; ++ priv->stats.txvidrop =0; ++ priv->stats.txvodrop =0; ++ priv->stats.txbeacondrop =0; ++ priv->stats.txmanagedrop =0; ++ ++ // priv->stats.txokbytestotal =0; ++//by amy ++ priv->LastSignalStrengthInPercent=0; ++ priv->SignalStrength=0; ++ priv->SignalQuality=0; ++ priv->antenna_flag=0; ++ priv->flag_beacon = false; ++//by amy ++//david ++ //radion on defaultly ++ priv->radion = 1; ++//david ++//by amy for rate adaptive ++ priv->CurrRetryCnt=0; ++ priv->LastRetryCnt=0; ++ priv->LastTxokCnt=0; ++ priv->LastRxokCnt=0; ++ priv->LastRetryRate=0; ++ priv->bTryuping=0; ++ priv->CurrTxRate=0; ++ priv->CurrRetryRate=0; ++ priv->TryupingCount=0; ++ priv->TryupingCountNoData=0; ++ priv->TryDownCountLowData=0; ++ priv->RecvSignalPower=0; ++ priv->LastTxOKBytes=0; ++ priv->LastFailTxRate=0; ++ priv->LastFailTxRateSS=0; ++ priv->FailTxRateCount=0; ++ priv->LastTxThroughput=0; ++ priv->txokbytestotal=0; ++//by amy for rate adaptive ++//by amy for ps ++ priv->RFChangeInProgress = false; ++ priv->SetRFPowerStateInProgress = false; ++ priv->RFProgType = 0; ++ priv->bInHctTest = false; ++ priv->bInactivePs = true;//false; ++ priv->ieee80211->bInactivePs = priv->bInactivePs; ++ priv->eInactivePowerState = eRfOn;//lzm add for IPS and Polling methord ++ priv->bSwRfProcessing = false; ++ priv->eRFPowerState = eRfOff; ++ priv->RfOffReason = 0; ++ priv->NumRxOkInPeriod = 0; ++ priv->NumTxOkInPeriod = 0; ++ priv->bLeisurePs = true; ++ priv->dot11PowerSaveMode = eActive; ++ priv->RegThreeWireMode=HW_THREE_WIRE_BY_8051; ++ priv->ps_mode = false; ++//by amy for ps ++//by amy for DIG ++ priv->bDigMechanism = 1; ++ priv->bCCKThMechanism = 0; ++ priv->InitialGain = 0; ++ priv->StageCCKTh = 0; ++ priv->RegBModeGainStage = 2; ++//by amy for DIG ++// {by david for DIG, 2008.3.6 ++ priv->RegDigOfdmFaUpTh = 0x0c; ++ priv->RegBModeGainStage = 0x02; ++ priv->DIG_NumberFallbackVote = 0; ++ priv->DIG_NumberUpgradeVote = 0; ++ priv->CCKUpperTh = 0x100; ++ priv->CCKLowerTh = 0x20; ++//} ++//{added by david for High tx power, 2008.3.11 ++ priv->bRegHighPowerMechanism = true; ++ priv->bToUpdateTxPwr = false; ++ ++ priv->Z2HiPwrUpperTh = 77; ++ priv->Z2HiPwrLowerTh = 75; ++ priv->Z2RSSIHiPwrUpperTh = 70; ++ priv->Z2RSSIHiPwrLowerTh = 20; ++ //specify for rtl8187B ++ priv->wMacRegRfPinsOutput = 0x0480; ++ priv->wMacRegRfPinsSelect = 0x2488; ++ // ++ // Note that, we just set TrSwState to TR_HW_CONTROLLED here instead of changing ++ // HW setting because we assume it should be inialized as HW controlled. 061010, by rcnjko. ++ // ++ priv->TrSwitchState = TR_HW_CONTROLLED; ++//} ++ priv->ieee80211->iw_mode = IW_MODE_INFRA; ++//test pending bug, john 20070815 ++ for(i=0;i<0x10;i++) atomic_set(&(priv->tx_pending[i]), 0); ++//by lizhaoming for LED ++#ifdef LED ++ priv->ieee80211->ieee80211_led_contorl = LedControl8187; ++#endif ++#ifdef CONFIG_IPS ++ priv->ieee80211->ieee80211_ips_leave = ieee80211_ips_leave;//IPSLeave; ++#endif ++ ++#ifdef SW_ANTE_DIVERSITY ++ priv->antb=0; ++ priv->diversity=1; ++ priv->LastRxPktAntenna = 0; ++ priv->AdMinCheckPeriod = 5; ++ priv->AdMaxCheckPeriod = 10; ++ // Lower signal strength threshold to fit the HW participation in antenna diversity. +by amy 080312 ++ priv->AdMaxRxSsThreshold = 30;//60->30 ++ priv->AdRxSsThreshold = 20;//50->20 ++ priv->AdCheckPeriod = priv->AdMinCheckPeriod; ++ priv->AdTickCount = 0; ++ priv->AdRxSignalStrength = -1; ++ priv->RegSwAntennaDiversityMechanism = 0; ++ priv->RegDefaultAntenna = 0; ++ priv->SignalStrength = 0; ++ priv->AdRxOkCnt = 0; ++ priv->CurrAntennaIndex = 0; ++ priv->AdRxSsBeforeSwitched = 0; ++ init_timer(&priv->SwAntennaDiversityTimer); ++ priv->SwAntennaDiversityTimer.data = (unsigned long)dev; ++ priv->SwAntennaDiversityTimer.function = (void *)SwAntennaDiversityTimerCallback; ++#endif ++ ++ priv->retry_rts = DEFAULT_RETRY_RTS; ++ priv->retry_data = DEFAULT_RETRY_DATA; ++ priv->ieee80211->rate = 110; //11 mbps ++ priv->CurrentOperaRate=priv->ieee80211->rate/5; ++ priv->ieee80211->short_slot = 1; ++ priv->ieee80211->mode = IEEE_G; ++ priv->promisc = (dev->flags & IFF_PROMISC) ? 1:0; ++ ++ rtl8180_link_detect_init(&priv->link_detect); ++ ++ spin_lock_init(&priv->tx_lock); ++ spin_lock_init(&priv->irq_lock);//added by thomas ++ spin_lock_init(&priv->rf_ps_lock); ++#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0)) ++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,20)) ++ INIT_WORK(&priv->reset_wq, (void*)rtl8180_restart); ++ INIT_WORK(&priv->ieee80211->ips_leave_wq, (void*)IPSLeave_wq); //YJ,add,081230,for IPS ++ INIT_DELAYED_WORK(&priv->ieee80211->rate_adapter_wq,(void*)rtl8180_rate_adapter); ++ INIT_DELAYED_WORK(&priv->ieee80211->hw_dig_wq,(void*)rtl8180_hw_dig_wq); ++ INIT_DELAYED_WORK(&priv->ieee80211->watch_dog_wq,(void*)rtl8180_watch_dog_wq); ++ INIT_DELAYED_WORK(&priv->ieee80211->tx_pw_wq,(void*)rtl8180_tx_pw_wq); ++ ++#ifdef SW_ANTE_DIVERSITY ++ INIT_DELAYED_WORK(&priv->ieee80211->SwAntennaWorkItem,(void*) SwAntennaWorkItemCallback); ++#endif ++ ++#else ++ INIT_WORK(&priv->reset_wq,(void*) rtl8180_restart,dev); ++ INIT_WORK(&priv->ieee80211->ips_leave_wq, (void*)IPSLeave_wq,dev); //YJ,add,081230,for IPS ++ INIT_WORK(&priv->ieee80211->rate_adapter_wq,(void*)rtl8180_rate_adapter,dev); ++ INIT_WORK(&priv->ieee80211->hw_dig_wq,(void*)rtl8180_hw_dig_wq,dev); ++ INIT_WORK(&priv->ieee80211->watch_dog_wq,(void*)rtl8180_watch_dog_wq,dev); ++ INIT_WORK(&priv->ieee80211->tx_pw_wq,(void*)rtl8180_tx_pw_wq,dev); ++ ++#ifdef SW_ANTE_DIVERSITY ++ INIT_WORK(&priv->ieee80211->SwAntennaWorkItem,(void*) SwAntennaWorkItemCallback, dev); ++#endif ++ ++#endif ++#else ++ tq_init(&priv->reset_wq,(void*) rtl8180_restart,dev); ++#endif ++ sema_init(&priv->wx_sem,1); ++ sema_init(&priv->set_chan_sem,1); ++#ifdef THOMAS_TASKLET ++ tasklet_init(&priv->irq_rx_tasklet, ++ (void(*)(unsigned long))rtl8180_irq_rx_tasklet_new, ++ (unsigned long)priv); ++#else ++ tasklet_init(&priv->irq_rx_tasklet, ++ (void(*)(unsigned long))rtl8180_irq_rx_tasklet, ++ (unsigned long)priv); ++#endif ++//by amy for rate adaptive ++ init_timer(&priv->rateadapter_timer); ++ priv->rateadapter_timer.data = (unsigned long)dev; ++ priv->rateadapter_timer.function = timer_rate_adaptive; ++//by amy for rate adaptive ++//by amy for ps ++ init_timer(&priv->watch_dog_timer); ++ priv->watch_dog_timer.data = (unsigned long)dev; ++ priv->watch_dog_timer.function = watch_dog_adaptive; ++//by amy ++//by amy for ps ++ priv->ieee80211->current_network.beacon_interval = DEFAULT_BEACONINTERVAL; ++ priv->ieee80211->iw_mode = IW_MODE_INFRA; ++ priv->ieee80211->softmac_features = IEEE_SOFTMAC_SCAN | ++ IEEE_SOFTMAC_ASSOCIATE | IEEE_SOFTMAC_PROBERQ | ++#ifdef CONFIG_SOFT_BEACON ++ IEEE_SOFTMAC_BEACONS | //IEEE_SOFTMAC_SINGLE_QUEUE; ++#endif ++ IEEE_SOFTMAC_PROBERS | IEEE_SOFTMAC_TX_QUEUE; ++ ++ priv->ieee80211->active_scan = 1; ++ //priv->ieee80211->ch_lock = 0; ++ priv->ieee80211->rate = 110; //11 mbps ++ priv->ieee80211->modulation = IEEE80211_CCK_MODULATION | IEEE80211_OFDM_MODULATION; ++ priv->ieee80211->host_encrypt = 1; ++ priv->ieee80211->host_decrypt = 1; ++#ifdef CONFIG_SOFT_BEACON ++ priv->ieee80211->start_send_beacons = NULL; ++ priv->ieee80211->stop_send_beacons = NULL; ++#else ++ priv->ieee80211->start_send_beacons = rtl8187_beacon_tx; ++ priv->ieee80211->stop_send_beacons = rtl8187_beacon_stop; ++#endif ++ priv->ieee80211->softmac_hard_start_xmit = rtl8180_hard_start_xmit; ++ priv->ieee80211->set_chan = rtl8180_set_chan; ++ priv->ieee80211->link_change = rtl8187_link_change; ++ priv->ieee80211->softmac_data_hard_start_xmit = rtl8180_hard_data_xmit; ++ priv->ieee80211->data_hard_stop = rtl8180_data_hard_stop; ++ priv->ieee80211->data_hard_resume = rtl8180_data_hard_resume; ++ ++#ifdef _RTL8187_EXT_PATCH_ ++ priv->ieee80211->meshScanMode = 0; ++ priv->mshobj = alloc_mshobj(priv); ++ if(priv->mshobj) ++ { ++ priv->ieee80211->ext_patch_ieee80211_start_protocol = priv->mshobj->ext_patch_ieee80211_start_protocol; ++ priv->ieee80211->ext_patch_ieee80211_stop_protocol = priv->mshobj->ext_patch_ieee80211_stop_protocol; ++//by amy for mesh ++ priv->ieee80211->ext_patch_ieee80211_start_mesh = priv->mshobj->ext_patch_ieee80211_start_mesh; ++//by amy for mesh ++ priv->ieee80211->ext_patch_ieee80211_probe_req_1 = priv->mshobj->ext_patch_ieee80211_probe_req_1; ++ priv->ieee80211->ext_patch_ieee80211_probe_req_2 = priv->mshobj->ext_patch_ieee80211_probe_req_2; ++ priv->ieee80211->ext_patch_ieee80211_association_req_1 = priv->mshobj->ext_patch_ieee80211_association_req_1; ++ priv->ieee80211->ext_patch_ieee80211_association_req_2 = priv->mshobj->ext_patch_ieee80211_association_req_2; ++ priv->ieee80211->ext_patch_ieee80211_assoc_resp_by_net_1 = priv->mshobj->ext_patch_ieee80211_assoc_resp_by_net_1; ++ priv->ieee80211->ext_patch_ieee80211_assoc_resp_by_net_2 = priv->mshobj->ext_patch_ieee80211_assoc_resp_by_net_2; ++ priv->ieee80211->ext_patch_ieee80211_rx_frame_softmac_on_auth = priv->mshobj->ext_patch_ieee80211_rx_frame_softmac_on_auth; ++ priv->ieee80211->ext_patch_ieee80211_rx_frame_softmac_on_deauth = priv->mshobj->ext_patch_ieee80211_rx_frame_softmac_on_deauth; ++ priv->ieee80211->ext_patch_ieee80211_rx_frame_softmac_on_assoc_req = priv->mshobj->ext_patch_ieee80211_rx_frame_softmac_on_assoc_req; ++ priv->ieee80211->ext_patch_ieee80211_rx_frame_softmac_on_assoc_rsp = priv->mshobj->ext_patch_ieee80211_rx_frame_softmac_on_assoc_rsp; ++ priv->ieee80211->ext_patch_ieee80211_ext_stop_scan_wq_set_channel = priv->mshobj->ext_patch_ieee80211_ext_stop_scan_wq_set_channel; ++ priv->ieee80211->ext_patch_ieee80211_process_probe_response_1 = priv->mshobj->ext_patch_ieee80211_process_probe_response_1; ++ priv->ieee80211->ext_patch_ieee80211_rx_mgt_on_probe_req = priv->mshobj->ext_patch_ieee80211_rx_mgt_on_probe_req; ++ priv->ieee80211->ext_patch_ieee80211_rx_mgt_update_expire = priv->mshobj->ext_patch_ieee80211_rx_mgt_update_expire; ++ priv->ieee80211->ext_patch_get_beacon_get_probersp = priv->mshobj->ext_patch_get_beacon_get_probersp; ++ priv->ieee80211->ext_patch_ieee80211_rx_on_rx = priv->mshobj->ext_patch_ieee80211_rx_on_rx; ++ priv->ieee80211->ext_patch_ieee80211_xmit = priv->mshobj->ext_patch_ieee80211_xmit; ++ priv->ieee80211->ext_patch_ieee80211_rx_frame_get_hdrlen = priv->mshobj->ext_patch_ieee80211_rx_frame_get_hdrlen; ++ priv->ieee80211->ext_patch_ieee80211_rx_is_valid_framectl = priv->mshobj->ext_patch_ieee80211_rx_is_valid_framectl; ++ priv->ieee80211->ext_patch_ieee80211_rx_process_dataframe = priv->mshobj->ext_patch_ieee80211_rx_process_dataframe; ++ // priv->ieee80211->ext_patch_is_duplicate_packet = priv->mshobj->ext_patch_is_duplicate_packet; ++ priv->ieee80211->ext_patch_ieee80211_softmac_xmit_get_rate = priv->mshobj->ext_patch_ieee80211_softmac_xmit_get_rate; ++ /* added by david for setting acl dynamically */ ++ priv->ieee80211->ext_patch_ieee80211_acl_query = priv->mshobj->ext_patch_ieee80211_acl_query; ++ } ++ ++#endif // _RTL8187_EXT_PATCH_ ++ ++#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0)) ++#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,20) ++ INIT_WORK(&priv->ieee80211->wmm_param_update_wq,\ ++ (void(*)(void*)) rtl8180_wmm_param_update,\ ++ priv->ieee80211); ++#else ++ INIT_WORK(&priv->ieee80211->wmm_param_update_wq,\ ++ rtl8180_wmm_param_update); ++#endif ++#else ++ tq_init(&priv->ieee80211->wmm_param_update_wq,\ ++ (void(*)(void*)) rtl8180_wmm_param_update,\ ++ priv->ieee80211); ++#endif ++ priv->ieee80211->init_wmmparam_flag = 0; ++ priv->ieee80211->fts = DEFAULT_FRAG_THRESHOLD; ++ ++ //priv->card_8185 = 2; ++ priv->phy_ver = 2; ++ priv->card_type = USB; ++//{add for 87B ++ priv->ShortRetryLimit = 7; ++ priv->LongRetryLimit = 7; ++ priv->EarlyRxThreshold = 7; ++ ++ priv->TransmitConfig = ++ TCR_DurProcMode | //for RTL8185B, duration setting by HW ++ TCR_DISReqQsize | ++ (TCR_MXDMA_2048<<TCR_MXDMA_SHIFT)| // Max DMA Burst Size per Tx DMA Burst, 7: reservied. ++ (priv->ShortRetryLimit<<TX_SRLRETRY_SHIFT)| // Short retry limit ++ (priv->LongRetryLimit<<TX_LRLRETRY_SHIFT) | // Long retry limit ++ (false ? TCR_SWPLCPLEN : 0); // FALSE: HW provies PLCP length and LENGEXT, TURE: SW proiveds them ++ ++ priv->ReceiveConfig = ++ RCR_AMF | RCR_ADF | //accept management/data ++ RCR_ACF | //accept control frame for SW AP needs PS-poll, 2005.07.07, by rcnjko. ++ RCR_AB | RCR_AM | RCR_APM | //accept BC/MC/UC ++ //RCR_AICV | RCR_ACRC32 | //accept ICV/CRC error packet ++ RCR_MXDMA | // Max DMA Burst Size per Rx DMA Burst, 7: unlimited. ++ (priv->EarlyRxThreshold<<RX_FIFO_THRESHOLD_SHIFT) | // Rx FIFO Threshold, 7: No Rx threshold. ++ (priv->EarlyRxThreshold == 7 ? RCR_ONLYERLPKT:0); ++ ++ priv->AcmControl = 0; ++//} ++ priv->rf_chip = 0xff & eprom_read(dev,EPROM_RFCHIPID); ++ //DMESG("rf_chip:%x\n", priv->rf_chip); ++ if (!priv->rf_chip) ++ { ++ DMESG("Can't get rf chip ID from EEPROM"); ++ DMESGW("So set rf chip ID to defalut EPROM_RFCHIPID_RTL8225U"); ++ DMESGW("use it with care and at your own risk and"); ++ DMESGW("**PLEASE** REPORT SUCCESS/INSUCCESS TO Realtek"); ++ priv->rf_chip = EPROM_RFCHIPID_RTL8225U; ++ ++ } ++ ++ ++//{put the card to detect different card here, mainly I/O processing ++ udev = priv->udev; ++ idProduct = le16_to_cpu(udev->descriptor.idProduct); ++ //idProduct = 0x8197; ++ bcdDevice = le16_to_cpu(udev->descriptor.bcdDevice); ++ DMESG("idProduct:0x%x, bcdDevice:0x%x", idProduct,bcdDevice); ++ switch (idProduct) { ++ case 0x8189: ++ case 0x8197: ++ case 0x8198: ++ /* check RF frontend chipset */ ++ priv->card_8187 = NIC_8187B; ++ priv->rf_init = rtl8225z2_rf_init; ++ priv->rf_set_chan = rtl8225z2_rf_set_chan; ++ priv->rf_set_sens = NULL; ++ break; ++ ++ case 0x8187: ++ if(bcdDevice == 0x0200){ ++ priv->card_8187 = NIC_8187B; ++ priv->rf_init = rtl8225z2_rf_init; ++ priv->rf_set_chan = rtl8225z2_rf_set_chan; ++ priv->rf_set_sens = NULL; ++ break; ++ }else{ ++ //0x0100 is for 8187 ++ //legacy 8187 NIC ++ //delet ++ ; ++ } ++ default: ++ /* check RF frontend chipset */ ++ priv->ieee80211->softmac_features |= IEEE_SOFTMAC_SINGLE_QUEUE; ++ priv->card_8187 = NIC_8187; ++ switch (priv->rf_chip) { ++ case EPROM_RFCHIPID_RTL8225U: ++ DMESG("Card reports RF frontend Realtek 8225"); ++ DMESGW("This driver has EXPERIMENTAL support for this chipset."); ++ DMESGW("use it with care and at your own risk and"); ++ DMESGW("**PLEASE** REPORT SUCCESS/INSUCCESS TO Realtek"); ++ if(rtl8225_is_V_z2(dev)){ ++ priv->rf_init = rtl8225z2_rf_init; ++ priv->rf_set_chan = rtl8225z2_rf_set_chan; ++ priv->rf_set_sens = NULL; ++ DMESG("This seems a new V2 radio"); ++ }else{ ++ priv->rf_init = rtl8225_rf_init; ++ priv->rf_set_chan = rtl8225_rf_set_chan; ++ priv->rf_set_sens = rtl8225_rf_set_sens; ++ DMESG("This seems a legacy 1st version radio"); ++ } ++ break; ++ ++ case EPROM_RFCHIPID_RTL8225U_VF: ++ priv->rf_init = rtl8225z2_rf_init; ++ priv->rf_set_chan = rtl8225z2_rf_set_chan; ++ priv->rf_set_sens = NULL; ++ DMESG("This seems a new V2 radio"); ++ break; ++ ++ default: ++ DMESGW("Unknown RF module %x",priv->rf_chip); ++ DMESGW("Exiting..."); ++ return -1; ++ } ++ break; ++ } ++ ++ priv->rf_close = rtl8225_rf_close; ++ priv->max_sens = RTL8225_RF_MAX_SENS; ++ priv->sens = RTL8225_RF_DEF_SENS; ++ ++#ifdef ENABLE_DOT11D ++#if 0 ++ for(i=0;i<0xFF;i++) { ++ if(i%16 == 0) ++ printk("\n[%x]: ", i/16); ++ printk("\t%4.4x", eprom_read(dev,i)); ++ } ++#endif ++ priv->channel_plan = eprom_read(dev,EPROM_CHANNEL_PLAN) & 0xFF; ++ //DMESG("EPROM_CHANNEL_PLAN is %x", priv->channel_plan); ++ ++ // lzm add 081205 for Toshiba: ++ // For Toshiba,reading the value from EEPROM 0x6h bit[7] to determine the priority of ++ // channel plan to be defined. ++ // -If bit[7] is true, then the channel plan is defined by EEPROM but no user defined. ++ // -If bit[7] is false, then the channel plan is defined by user first. ++ // ++ if(priv->channel_plan & 0x80) { ++ DMESG("Toshiba channel plan is defined by EEPROM"); ++ priv->channel_plan &= 0xf; ++ } ++ else ++ priv->channel_plan = 0; ++ ++ //if(priv->channel_plan > COUNTRY_CODE_WORLD_WIDE_13_INDEX){ ++ if(priv->channel_plan > COUNTRY_CODE_GLOBAL_DOMAIN){ ++ DMESG("rtl8180_init:Error channel plan! Set to default.\n"); ++ priv->channel_plan = 0; ++ } ++ ++ //priv->channel_plan = 9; //Global Domain ++ //priv->channel_plan = 2; //ETSI ++ ++ ++ DMESG("Channel plan is %d ",priv->channel_plan); ++ ++ //for Toshiba card we read channel plan from ChanPlanBin ++ if((idProduct != 0x8197) && (idProduct != 0x8198)) ++ rtl8180_set_channel_map(priv->channel_plan, priv->ieee80211); ++#else ++ int ch; ++ priv->channel_plan = eprom_read(dev,EPROM_CHANNEL_PLAN) & 0xff; ++ if(priv->channel_plan & 0x80) { ++ priv->channel_plan &= 0x7f; ++ if (ChannelPlan[priv->channel_plan].Len != 0){ ++ // force channel plan map ++ for (i=0;i<ChannelPlan[priv->channel_plan].Len;i++) ++ priv->ieee80211->channel_map[ChannelPlan[priv->channel_plan].Channel[i]] = 1; ++ } else { ++ DMESG("No channels, aborting"); ++ return -1; ++ } ++ } else { ++ //default channel plan setting ++ if(!channels){ ++ DMESG("No channels, aborting"); ++ return -1; ++ } ++ ch=channels; ++ // set channels 1..14 allowed in given locale ++ for (i=1; i<=14; i++) { ++ (priv->ieee80211->channel_map)[i] = (u8)(ch & 0x01); ++ ch >>= 1; ++ } ++ } ++#endif ++ ++ if((idProduct == 0x8197) || (idProduct == 0x8198)) { ++ // lzm add 081205 for Toshiba: ++ // 0x77h bit[0]=1: use GPIO bit[2], bit[0]=0: use GPIO bit[1] ++ priv->EEPROMSelectNewGPIO =((u8)((eprom_read(dev,EPROM_SELECT_GPIO) & 0xff00) >> 8)) ? true : false; ++ DMESG("EPROM_SELECT_GPIO:%d", priv->EEPROMSelectNewGPIO); ++ } else { ++ priv->EEPROMSelectNewGPIO = false; ++ } ++ ++ ++ if (NIC_8187 == priv->card_8187){ ++ hw_version =( read_nic_dword(dev, TCR) & TCR_HWVERID_MASK)>>TCR_HWVERID_SHIFT; ++ switch (hw_version) { ++ case 0x06: ++ //priv->card_8187_Bversion = VERSION_8187B_B; ++ break; ++ case 0x05: ++ priv->card_8187_Bversion = VERSION_8187_D; ++ break; ++ default: ++ priv->card_8187_Bversion = VERSION_8187_B; ++ break; ++ } ++ }else{ ++ hw_version = read_nic_byte(dev, 0xe1); //87B hw version reg ++ switch (hw_version){ ++ case 0x00: ++ priv->card_8187_Bversion = VERSION_8187B_B; ++ break; ++ case 0x01: ++ priv->card_8187_Bversion = VERSION_8187B_D; ++ break; ++ case 0x02: ++ priv->card_8187_Bversion = VERSION_8187B_E; ++ break; ++ default: ++ priv->card_8187_Bversion = VERSION_8187B_B; //defalt ++ break; ++ } ++ } ++ ++ //printk("=====hw_version:%x\n", priv->card_8187_Bversion); ++ priv->enable_gpio0 = 0; ++ ++ /*the eeprom type is stored in RCR register bit #6 */ ++ if (RCR_9356SEL & read_nic_dword(dev, RCR)){ ++ priv->epromtype=EPROM_93c56; ++ DMESG("Reported EEPROM chip is a 93c56 (2Kbit)"); ++ }else{ ++ priv->epromtype=EPROM_93c46; ++ DMESG("Reported EEPROM chip is a 93c46 (1Kbit)"); ++ } ++ ++ dev->dev_addr[0]=eprom_read(dev,MAC_ADR) & 0xff; ++ dev->dev_addr[1]=(eprom_read(dev,MAC_ADR) & 0xff00)>>8; ++ dev->dev_addr[2]=eprom_read(dev,MAC_ADR+1) & 0xff; ++ dev->dev_addr[3]=(eprom_read(dev,MAC_ADR+1) & 0xff00)>>8; ++ dev->dev_addr[4]=eprom_read(dev,MAC_ADR+2) & 0xff; ++ dev->dev_addr[5]=((eprom_read(dev,MAC_ADR+2) & 0xff00)>>8)+1; ++ ++ DMESG("Card MAC address is "MAC_FMT, MAC_ARG(dev->dev_addr)); ++ ++ for(i=1,j=0; i<6; i+=2,j++){ ++ ++ word = eprom_read(dev,EPROM_TXPW0 + j); ++ priv->chtxpwr[i]=word & 0xf; ++ priv->chtxpwr_ofdm[i]=(word & 0xf0)>>4; ++ priv->chtxpwr[i+1]=(word & 0xf00)>>8; ++ priv->chtxpwr_ofdm[i+1]=(word & 0xf000)>>12; ++ } ++ ++ for(i=1,j=0; i<4; i+=2,j++){ ++ ++ word = eprom_read(dev,EPROM_TXPW1 + j); ++ priv->chtxpwr[i+6]=word & 0xf; ++ priv->chtxpwr_ofdm[i+6]=(word & 0xf0)>>4; ++ priv->chtxpwr[i+6+1]=(word & 0xf00)>>8; ++ priv->chtxpwr_ofdm[i+6+1]=(word & 0xf000)>>12; ++ } ++ if (priv->card_8187 == NIC_8187){ ++ for(i=1,j=0; i<4; i+=2,j++){ ++ word = eprom_read(dev,EPROM_TXPW2 + j); ++ priv->chtxpwr[i+6+4]=word & 0xf; ++ priv->chtxpwr_ofdm[i+6+4]=(word & 0xf0)>>4; ++ priv->chtxpwr[i+6+4+1]=(word & 0xf00)>>8; ++ priv->chtxpwr_ofdm[i+6+4+1]=(word & 0xf000)>>12; ++ } ++ } else{ ++ word = eprom_read(dev, 0x1B) & 0xff; //channel 11; ++ priv->chtxpwr[11]=word & 0xf; ++ priv->chtxpwr_ofdm[11] = (word & 0xf0)>>4; ++ ++ word = eprom_read(dev, 0xA) & 0xff; //channel 12; ++ priv->chtxpwr[12]=word & 0xf; ++ priv->chtxpwr_ofdm[12] = (word & 0xf0)>>4; ++ ++ word = eprom_read(dev, 0x1c) ; //channel 13 ,14; ++ priv->chtxpwr[13]=word & 0xf; ++ priv->chtxpwr_ofdm[13] = (word & 0xf0)>>4; ++ priv->chtxpwr[14]=(word & 0xf00)>>8; ++ priv->chtxpwr_ofdm[14] = (word & 0xf000)>>12; ++ } ++ ++ word = eprom_read(dev,EPROM_TXPW_BASE); ++ priv->cck_txpwr_base = word & 0xf; ++ priv->ofdm_txpwr_base = (word>>4) & 0xf; ++ ++ //DMESG("PAPE from CONFIG2: %x",read_nic_byte(dev,CONFIG2)&0x7); ++ ++#ifdef SW_ANTE_DIVERSITY ++ rtl8187_antenna_diversity_read(dev); ++#endif ++ ++ if(rtl8187_usb_initendpoints(dev)!=0){ ++ DMESG("Endopoints initialization failed"); ++ return -ENOMEM; ++ } ++#ifdef LED ++ InitSwLeds(dev); ++#endif ++#ifdef DEBUG_EPROM ++ dump_eprom(dev); ++#endif ++ return 0; ++ ++} ++ ++void rtl8185_rf_pins_enable(struct net_device *dev) ++{ ++/* u16 tmp; ++ tmp = read_nic_word(dev, RFPinsEnable);*/ ++ write_nic_word(dev, RFPinsEnable, 0x1ff7);// | tmp); ++} ++ ++ ++void rtl8185_set_anaparam2(struct net_device *dev, u32 a) ++{ ++ u8 conf3; ++ ++ rtl8180_set_mode(dev, EPROM_CMD_CONFIG); ++ ++ conf3 = read_nic_byte(dev, CONFIG3); ++ write_nic_byte(dev, CONFIG3, conf3 | (1<<CONFIG3_ANAPARAM_W_SHIFT)); ++ ++ write_nic_dword(dev, ANAPARAM2, a); ++ ++ conf3 = read_nic_byte(dev, CONFIG3); ++ write_nic_byte(dev, CONFIG3, conf3 &~(1<<CONFIG3_ANAPARAM_W_SHIFT)); ++ ++ rtl8180_set_mode(dev, EPROM_CMD_NORMAL); ++ ++} ++ ++ ++void rtl8180_set_anaparam(struct net_device *dev, u32 a) ++{ ++ u8 conf3; ++ ++ rtl8180_set_mode(dev, EPROM_CMD_CONFIG); ++ ++ conf3 = read_nic_byte(dev, CONFIG3); ++ write_nic_byte(dev, CONFIG3, conf3 | (1<<CONFIG3_ANAPARAM_W_SHIFT)); ++ ++ write_nic_dword(dev, ANAPARAM, a); ++ ++ conf3 = read_nic_byte(dev, CONFIG3); ++ write_nic_byte(dev, CONFIG3, conf3 &~(1<<CONFIG3_ANAPARAM_W_SHIFT)); ++ ++ rtl8180_set_mode(dev, EPROM_CMD_NORMAL); ++ ++} ++ ++ ++void rtl8185_tx_antenna(struct net_device *dev, u8 ant) ++{ ++ write_nic_byte(dev, ANTSEL, ant); ++ //lzm mod for up take too long time 20081201 ++ //mdelay(1); ++} ++ ++ ++void rtl8187_write_phy(struct net_device *dev, u8 adr, u32 data) ++{ ++ u32 phyw; ++ ++ adr |= 0x80; ++ ++ phyw= ((data<<8) | adr); ++ ++ ++ ++ // Note that, we must write 0xff7c after 0x7d-0x7f to write BB register. ++ write_nic_byte(dev, 0x7f, ((phyw & 0xff000000) >> 24)); ++ write_nic_byte(dev, 0x7e, ((phyw & 0x00ff0000) >> 16)); ++ write_nic_byte(dev, 0x7d, ((phyw & 0x0000ff00) >> 8)); ++ write_nic_byte(dev, 0x7c, ((phyw & 0x000000ff) )); ++ ++ //read_nic_dword(dev, PHY_ADR); ++#if 0 ++ for(i=0;i<10;i++){ ++ write_nic_dword(dev, PHY_ADR, 0xffffff7f & phyw); ++ phyr = read_nic_byte(dev, PHY_READ); ++ if(phyr == (data&0xff)) break; ++ ++ } ++#endif ++ /* this is ok to fail when we write AGC table. check for AGC table might be ++ * done by masking with 0x7f instead of 0xff */ ++ //if(phyr != (data&0xff)) DMESGW("Phy write timeout %x %x %x", phyr, data, adr); ++ //msdelay(1);//CPU occupany is too high. LZM 31/10/2008 ++} ++ ++u8 rtl8187_read_phy(struct net_device *dev,u8 adr, u32 data) ++{ ++ u32 phyw; ++ ++ adr &= ~0x80; ++ phyw= ((data<<8) | adr); ++ ++ ++ // Note that, we must write 0xff7c after 0x7d-0x7f to write BB register. ++ write_nic_byte(dev, 0x7f, ((phyw & 0xff000000) >> 24)); ++ write_nic_byte(dev, 0x7e, ((phyw & 0x00ff0000) >> 16)); ++ write_nic_byte(dev, 0x7d, ((phyw & 0x0000ff00) >> 8)); ++ write_nic_byte(dev, 0x7c, ((phyw & 0x000000ff) )); ++ ++ return(read_nic_byte(dev,0x7e)); ++ ++} ++ ++u8 read_phy_ofdm(struct net_device *dev, u8 adr) ++{ ++ return(rtl8187_read_phy(dev, adr, 0x000000)); ++} ++ ++u8 read_phy_cck(struct net_device *dev, u8 adr) ++{ ++ return(rtl8187_read_phy(dev, adr, 0x10000)); ++} ++ ++inline void write_phy_ofdm (struct net_device *dev, u8 adr, u32 data) ++{ ++ data = data & 0xff; ++ rtl8187_write_phy(dev, adr, data); ++} ++ ++ ++void write_phy_cck (struct net_device *dev, u8 adr, u32 data) ++{ ++ data = data & 0xff; ++ rtl8187_write_phy(dev, adr, data | 0x10000); ++} ++// ++// Description: Change ZEBRA's power state. ++// ++// Assumption: This function must be executed in PASSIVE_LEVEL. ++// ++// 061214, by rcnjko. ++// ++//#define MAX_DOZE_WAITING_TIMES_87B 1000//500 ++#define MAX_DOZE_WAITING_TIMES_87B_MOD 500 ++ ++bool SetZebraRFPowerState8187B(struct net_device *dev,RT_RF_POWER_STATE eRFPowerState) ++{ ++ struct r8180_priv *priv = ieee80211_priv(dev); ++ u8 btCR9346, btConfig3; ++ bool bResult = true; ++ int i; ++ u16 u2bTFPC = 0; ++ u8 u1bTmp; ++ ++ // Set EEM0 and EEM1 in 9346CR. ++ btCR9346 = read_nic_byte(dev, CR9346); ++ write_nic_byte(dev, CR9346, (btCR9346|0xC0) ); ++ // Set PARM_En in Config3. ++ btConfig3 = read_nic_byte(dev, CONFIG3); ++ write_nic_byte(dev, CONFIG3, (btConfig3|CONFIG3_PARM_En) ); ++ // BB and RF related operations: ++ switch(eRFPowerState) ++ { ++ case eRfOn: ++#ifdef CONFIG_RADIO_DEBUG ++ DMESG("Now Radio ON!"); ++#endif ++ write_nic_dword(dev, ANAPARAM, ANAPARM_ON); ++ write_nic_dword(dev, ANAPARAM2, ANAPARM2_ON); ++ //write_nic_byte(dev, CONFIG4, (priv->RFProgType)); ++ ++ write_nic_byte(dev, 0x085, 0x24); // 061219, SD3 ED: for minicard CCK power leakage issue. ++ write_rtl8225(dev, 0x4, 0x9FF); ++ mdelay(1); ++ // ++ // <Roger_Notes> We reset PLL to reduce power consumption about 30 mA. 2008.01.16. ++ // ++ { ++ u8 Reg62; ++ ++ write_nic_byte(dev, 0x61, 0x10); ++ Reg62 = read_nic_byte(dev, 0x62); ++ write_nic_byte(dev, 0x62, (Reg62 & (~BIT5)) ); ++ write_nic_byte(dev, 0x62, (Reg62 | BIT5) ); // Enable PLL. ++ } ++ ++ u1bTmp = read_nic_byte(dev, 0x24E); ++ write_nic_byte(dev, 0x24E, (u1bTmp & (~(BIT5|BIT6))) );// 070124 SD1 Alex: turn on CCK and OFDM. ++ break; ++ ++ case eRfSleep: ++#ifdef CONFIG_RADIO_DEBUG ++ DMESG("Now Radio Sleep!"); ++#endif ++ for(i = 0; i < MAX_DOZE_WAITING_TIMES_87B_MOD; i++) ++ { // Make sure TX FIFO is empty befor turn off RFE pwoer. ++ u2bTFPC = read_nic_word(dev, TFPC); ++ if(u2bTFPC == 0){ ++ //printk("%d times TFPC: %d == 0 before doze...\n", (i+1), u2bTFPC); ++ break; ++ }else{ ++ //printk("%d times TFPC: %d != 0 before doze!\n", (i+1), u2bTFPC); ++ udelay(10); ++ } ++ } ++ ++ if( i == MAX_DOZE_WAITING_TIMES_87B_MOD ){ ++ //printk("\n\n\n SetZebraRFPowerState8187B(): %d times TFPC: %d != 0 !!!\n\n\n", MAX_DOZE_WAITING_TIMES_87B_MOD, u2bTFPC); ++ } ++ ++ u1bTmp = read_nic_byte(dev, 0x24E); ++ write_nic_byte(dev, 0x24E, (u1bTmp|BIT5|BIT6));// 070124 SD1 Alex: turn off CCK and OFDM. ++ ++ write_rtl8225(dev, 0x4, 0xDFF); // Turn off RF first to prevent BB lock up, suggested by PJ, 2006.03.03. ++ write_nic_byte(dev, 0x085, 0x04); // 061219, SD3 ED: for minicard CCK power leakage issue. ++ ++ //write_nic_byte(dev, CONFIG4, (priv->RFProgType|Config4_PowerOff)); ++ ++ write_nic_dword(dev, ANAPARAM, ANAPARM_OFF); ++ write_nic_dword(dev, ANAPARAM2, 0x72303f70); // 070126, by SD1 William. ++ break; ++ ++ case eRfOff: ++#ifdef CONFIG_RADIO_DEBUG ++ DMESG("Now Radio OFF!"); ++#endif ++ for(i = 0; i < MAX_DOZE_WAITING_TIMES_87B_MOD; i++) ++ { // Make sure TX FIFO is empty befor turn off RFE pwoer. ++ u2bTFPC = read_nic_word(dev, TFPC); ++ if(u2bTFPC == 0) { ++ //printk("%d times TFPC: %d == 0 before doze...\n", (i+1), u2bTFPC); ++ break; ++ }else{ ++ //printk("%d times TFPC: 0x%x != 0 before doze!\n", (i+1), u2bTFPC); ++ udelay(10); ++ } ++ } ++ ++ if( i == MAX_DOZE_WAITING_TIMES_87B_MOD){ ++ //printk("\n\n\nSetZebraRFPowerState8187B(): %d times TFPC: 0x%x != 0 !!!\n\n\n", MAX_DOZE_WAITING_TIMES_87B_MOD, u2bTFPC); ++ } ++ ++ u1bTmp = read_nic_byte(dev, 0x24E); ++ write_nic_byte(dev, 0x24E, (u1bTmp|BIT5|BIT6));// 070124 SD1 Alex: turn off CCK and OFDM. ++ ++ write_rtl8225(dev, 0x4,0x1FF); // Turn off RF first to prevent BB lock up, suggested by PJ, 2006.03.03. ++ write_nic_byte(dev, 0x085, 0x04); // 061219, SD3 ED: for minicard CCK power leakage issue. ++ ++ //write_nic_byte(dev, CONFIG4, (priv->RFProgType|Config4_PowerOff)); ++ ++ write_nic_dword(dev, ANAPARAM, ANAPARM_OFF); ++ write_nic_dword(dev, ANAPARAM2, ANAPARM2_OFF); // 070301, SD1 William: to reduce RF off power consumption to 80 mA. ++ break; ++ ++ default: ++ bResult = false; ++ //printk("SetZebraRFPowerState8187B(): unknow state to set: 0x%X!!!\n", eRFPowerState); ++ break; ++ } ++ ++ // Clear PARM_En in Config3. ++ btConfig3 &= ~(CONFIG3_PARM_En); ++ write_nic_byte(dev, CONFIG3, btConfig3); ++ // Clear EEM0 and EEM1 in 9346CR. ++ btCR9346 &= ~(0xC0); ++ write_nic_byte(dev, CR9346, btCR9346); ++ ++ if(bResult){ ++ // Update current RF state variable. ++ priv->eRFPowerState = eRFPowerState; ++ } ++ ++ return bResult; ++} ++//by amy for ps ++// ++// Description: Chang RF Power State. ++// Note that, only MgntActSet_RF_State() is allowed to set HW_VAR_RF_STATE. ++// ++// Assumption:PASSIVE LEVEL. ++// ++bool SetRFPowerState(struct net_device *dev,RT_RF_POWER_STATE eRFPowerState) ++{ ++ struct r8180_priv *priv = (struct r8180_priv *)ieee80211_priv(dev); ++ bool bResult = false; ++ ++ //printk("---------> SetRFPowerState(): eRFPowerState(%d)\n", eRFPowerState); ++ if(eRFPowerState == priv->eRFPowerState) ++ { ++ //printk("<--------- SetRFPowerState(): discard the request for eRFPowerState(%d) is the same.\n", eRFPowerState); ++ return bResult; ++ } ++ ++ switch(priv->rf_chip) ++ { ++ case RF_ZEBRA2: ++ bResult = SetZebraRFPowerState8187B(dev, eRFPowerState); ++ break; ++ ++ default: ++ printk("SetRFPowerState8185(): unknown RFChipID: 0x%X!!!\n", priv->rf_chip); ++ break;; ++ } ++ //printk("<--------- SetRFPowerState(): bResult(%d)\n", bResult); ++ ++ return bResult; ++} ++ ++bool ++MgntActSet_RF_State(struct net_device *dev,RT_RF_POWER_STATE StateToSet,u32 ChangeSource) ++{ ++ struct r8180_priv *priv = (struct r8180_priv *)ieee80211_priv(dev); ++ bool bActionAllowed = false; ++ bool bConnectBySSID = false; ++ RT_RF_POWER_STATE rtState; ++ u16 RFWaitCounter = 0; ++ unsigned long flag; ++ // printk("===>MgntActSet_RF_State(): StateToSet(%d), ChangeSource(0x%x)\n",StateToSet, ChangeSource); ++ // ++ // Prevent the race condition of RF state change. By Bruce, 2007-11-28. ++ // Only one thread can change the RF state at one time, and others should wait to be executed. ++ // ++#if 1 ++ while(true) ++ { ++ //down(&priv->rf_state); ++ spin_lock_irqsave(&priv->rf_ps_lock,flag); ++ if(priv->RFChangeInProgress) ++ { ++ //up(&priv->rf_state); ++ //RT_TRACE(COMP_RF, DBG_LOUD, ("MgntActSet_RF_State(): RF Change in progress! Wait to set..StateToSet(%d).\n", StateToSet)); ++ spin_unlock_irqrestore(&priv->rf_ps_lock,flag); ++ // Set RF after the previous action is done. ++ while(priv->RFChangeInProgress) ++ { ++ RFWaitCounter ++; ++ //RT_TRACE(COMP_RF, DBG_LOUD, ("MgntActSet_RF_State(): Wait 1 ms (%d times)...\n", RFWaitCounter)); ++ udelay(1000); // 1 ms ++ ++ // Wait too long, return FALSE to avoid to be stuck here. ++ if(RFWaitCounter > 1000) // 1sec ++ { ++ // DMESG("MgntActSet_RF_State(): Wait too long to set RF"); ++ // TODO: Reset RF state? ++ return false; ++ } ++ } ++ } ++ else ++ { ++ priv->RFChangeInProgress = true; ++// up(&priv->rf_state); ++ spin_unlock_irqrestore(&priv->rf_ps_lock,flag); ++ break; ++ } ++ } ++#endif ++ rtState = priv->eRFPowerState; ++ ++ switch(StateToSet) ++ { ++ case eRfOn: ++ // ++ // Turn On RF no matter the IPS setting because we need to update the RF state to Ndis under Vista, or ++ // the Windows does not allow the driver to perform site survey any more. By Bruce, 2007-10-02. ++ // ++ // leave last reasons and kick this reason till priv->RfOffReason = 0; ++ // if one reason turn radio off check if off->on reason is the same.if so turn, or reject it. ++ // if more than 1 reasons turn radio off we only turn on radio when all reasons turn on radio, ++ // so first turn on trys will reject till priv->RfOffReason = 0; ++ priv->RfOffReason &= (~ChangeSource); ++ ++ if(! priv->RfOffReason) ++ { ++ priv->RfOffReason = 0; ++ bActionAllowed = true; ++ ++ if(rtState == eRfOff && ChangeSource >=RF_CHANGE_BY_HW && !priv->bInHctTest) ++ { ++ bConnectBySSID = true; ++ } ++ } else { ++ ;//lzm must or TX_PENDING 12>MAX_TX_URB ++ //printk("Turn Radio On Reject because RfOffReason= 0x%x, ChangeSource=0x%X\n", priv->RfOffReason, ChangeSource); ++ } ++ break; ++ ++ case eRfOff: ++ // 070125, rcnjko: we always keep connected in AP mode. ++ if (priv->RfOffReason > RF_CHANGE_BY_IPS) ++ { ++ // ++ // 060808, Annie: ++ // Disconnect to current BSS when radio off. Asked by QuanTa. ++ // ++ ++ // ++ // Calling MgntDisconnect() instead of MgntActSet_802_11_DISASSOCIATE(), ++ // because we do NOT need to set ssid to dummy ones. ++ // Revised by Roger, 2007.12.04. ++ // ++//by amy not supported ++ //MgntDisconnect( dev, disas_lv_ss ); ++ ++ // Clear content of bssDesc[] and bssDesc4Query[] to avoid reporting old bss to UI. ++ // 2007.05.28, by shien chang. ++ //PlatformZeroMemory( pMgntInfo->bssDesc, sizeof(RT_WLAN_BSS)*MAX_BSS_DESC ); ++ //pMgntInfo->NumBssDesc = 0; ++ //PlatformZeroMemory( pMgntInfo->bssDesc4Query, sizeof(RT_WLAN_BSS)*MAX_BSS_DESC ); ++ //pMgntInfo->NumBssDesc4Query = 0; ++ } ++ ++ ++ ++ priv->RfOffReason |= ChangeSource; ++ bActionAllowed = true; ++ //printk("Turn Radio Off RfOffReason= 0x%x, ChangeSource=0x%X\n", priv->RfOffReason, ChangeSource); ++ break; ++ ++ case eRfSleep: ++ priv->RfOffReason |= ChangeSource; ++ bActionAllowed = true; ++ break; ++ ++ default: ++ break; ++ } ++ ++ if(bActionAllowed) ++ { ++ // Config HW to the specified mode. ++ //printk("MgntActSet_RF_State(): Action is allowed.... StateToSet(%d), RfOffReason(%#X)\n", StateToSet, priv->RfOffReason); ++ SetRFPowerState(dev, StateToSet); ++ // Turn on RF. ++ if(StateToSet == eRfOn) ++ { ++ //HalEnableRx8185Dummy(dev); ++ if(bConnectBySSID) ++ { ++ // by amy not supported ++ //MgntActSet_802_11_SSID(Adapter, Adapter->MgntInfo.Ssid.Octet, Adapter->MgntInfo.Ssid.Length, TRUE ); ++ } ++ } ++ // Turn off RF. ++ else if(StateToSet == eRfOff) ++ { ++ //HalDisableRx8185Dummy(dev); ++ } ++ } ++ else ++ { ++ //printk("Action is rejected.... StateToSet(%d), ChangeSource(%#X), RfOffReason(%#X)\n", ++ // StateToSet, ChangeSource, priv->RfOffReason); ++ } ++ ++ // Release RF spinlock ++ //down(&priv->rf_state); ++ spin_lock_irqsave(&priv->rf_ps_lock,flag); ++ priv->RFChangeInProgress = false; ++ //up(&priv->rf_state); ++ spin_unlock_irqrestore(&priv->rf_ps_lock,flag); ++ return bActionAllowed; ++} ++//by amy for ps ++ ++void rtl8180_adapter_start(struct net_device *dev) ++{ ++ struct r8180_priv *priv = ieee80211_priv(dev); ++// struct ieee80211_device *ieee = priv->ieee80211; ++// u8 InitWirelessMode; ++// u8 SupportedWirelessMode; ++// bool bInvalidWirelessMode = false; ++ ++ ++ if(NIC_8187 == priv->card_8187) { ++ //rtl8180_rtx_disable(dev); ++ rtl8180_reset(dev); ++ ++ write_nic_byte(dev,0x85,0); ++ write_nic_byte(dev,0x91,0); ++ ++ /* light blink! */ ++ write_nic_byte(dev,0x85,4); ++ write_nic_byte(dev,0x91,1); ++ write_nic_byte(dev,0x90,0); ++ ++ //by lizhaoming for LED POWR ON ++ //LedControl8187(dev, LED_CTL_POWER_ON); ++ ++ /* ++ write_nic_byte(dev, CR9346, 0xC0); ++ //LED TYPE ++ write_nic_byte(dev, CONFIG1,((read_nic_byte(dev, CONFIG1)&0x3f)|0x80)); //turn on bit 5:Clkrun_mode ++ write_nic_byte(dev, CR9346, 0x0); // disable config register write ++ */ ++ priv->irq_mask = 0xffff; ++ /* ++ priv->dma_poll_mask = 0; ++ priv->dma_poll_mask|= (1<<TX_DMA_STOP_BEACON_SHIFT); ++ */ ++ // rtl8180_beacon_tx_disable(dev); ++ ++ rtl8180_set_mode(dev, EPROM_CMD_CONFIG); ++ write_nic_dword(dev, MAC0, ((u32*)dev->dev_addr)[0]); ++ write_nic_word(dev, MAC4, ((u32*)dev->dev_addr)[1] & 0xffff ); ++ ++ rtl8180_set_mode(dev, EPROM_CMD_NORMAL); ++ rtl8180_update_msr(dev); ++ ++ rtl8180_set_mode(dev, EPROM_CMD_CONFIG); ++ ++ write_nic_word(dev,0xf4,0xffff); ++ write_nic_byte(dev, ++ CONFIG1, (read_nic_byte(dev,CONFIG1) & 0x3f) | 0x80); ++ ++ rtl8180_set_mode(dev,EPROM_CMD_NORMAL); ++ ++ write_nic_dword(dev,INT_TIMEOUT,0); ++ ++#ifdef DEBUG_REGISTERS ++ rtl8180_dump_reg(dev); ++#endif ++ ++ ++ write_nic_byte(dev, WPA_CONFIG, 0); ++ ++ write_nic_byte(dev, RATE_FALLBACK, 0x81); ++ rtl8187_set_rate(dev); ++ ++ priv->rf_init(dev); ++ ++ if(priv->rf_set_sens != NULL) { ++ priv->rf_set_sens(dev,priv->sens); ++ } ++ ++ write_nic_word(dev,0x5e,1); ++ //mdelay(1); ++ write_nic_word(dev,0xfe,0x10); ++ // mdelay(1); ++ write_nic_byte(dev, TALLY_SEL, 0x80);//Set NQ retry count ++ write_nic_byte(dev, 0xff, 0x60); ++ write_nic_word(dev,0x5e,0); ++ ++ rtl8180_irq_enable(dev); ++ } else { ++ /** ++ * IO part migrated from Windows Driver. ++ */ ++ priv->irq_mask = 0xffff; ++ // Enable Config3.PARAM_En. ++ write_nic_byte(dev, CR9346, 0xC0); ++ ++ write_nic_byte(dev, CONFIG3, (read_nic_byte(dev, CONFIG3)| CONFIG3_PARM_En|CONFIG3_GNTSel)); ++ // Turn on Analog power. ++ // setup A/D D/A parameter for 8185 b2 ++ // Asked for by William, otherwise, MAC 3-wire can't work, 2006.06.27, by rcnjko. ++ write_nic_dword(dev, ANA_PARAM2, ANAPARM2_ASIC_ON); ++ write_nic_dword(dev, ANA_PARAM, ANAPARM_ASIC_ON); ++ write_nic_byte(dev, ANA_PARAM3, 0x00); ++ ++ //by lizhaoming for LED POWR ON ++ //LedControl8187(dev, LED_CTL_POWER_ON); ++ ++ {//added for reset PLL ++ u8 bReg62; ++ write_nic_byte(dev, 0x61, 0x10); ++ bReg62 = read_nic_byte(dev, 0x62); ++ write_nic_byte(dev, 0x62, bReg62&(~(0x1<<5))); ++ write_nic_byte(dev, 0x62, bReg62|(0x1<<5)); ++ } ++ write_nic_byte(dev, CONFIG3, (read_nic_byte(dev, CONFIG3)&(~CONFIG3_PARM_En))); ++ write_nic_byte(dev, CR9346, 0x00); ++ ++ //rtl8180_rtx_disable(dev); ++ rtl8180_reset(dev); ++ write_nic_byte(dev, CR9346, 0xc0); // enable config register write ++ priv->rf_init(dev); ++ // Enable tx/rx ++ ++ write_nic_byte(dev, CMD, (CR_RE|CR_TE));// Using HW_VAR_COMMAND instead of writing CMDR directly. Rewrited by Annie, 2006-04-07. ++ ++ //add this is for 8187B Rx stall problem ++ ++ rtl8180_irq_enable(dev); ++ ++ write_nic_byte_E(dev, 0x41, 0xF4); ++ write_nic_byte_E(dev, 0x40, 0x00); ++ write_nic_byte_E(dev, 0x42, 0x00); ++ write_nic_byte_E(dev, 0x42, 0x01); ++ write_nic_byte_E(dev, 0x40, 0x0F); ++ write_nic_byte_E(dev, 0x42, 0x00); ++ write_nic_byte_E(dev, 0x42, 0x01); ++ ++ // 8187B demo board MAC and AFE power saving parameters from SD1 William, 2006.07.20. ++ // Parameter revised by SD1 William, 2006.08.21: ++ // 373h -> 0x4F // Original: 0x0F ++ // 377h -> 0x59 // Original: 0x4F ++ // Victor 2006/8/21: ¬Ù¹q°Ñ¼Æ«Øijµ¥SD3 °ª§C·Å and cable link test OK¤~¥¿¦¡ release,¤£«Øij¤Ó§Ö ++ // 2006/9/5, Victor & ED: it is OK to use. ++ //if(pHalData->RegBoardType == BT_DEMO_BOARD) ++ //{ ++ // AFE. ++ // ++ // Revise the content of Reg0x372, 0x374, 0x378 and 0x37a to fix unusual electronic current ++ // while CTS-To-Self occurs, by DZ's request. ++ // Modified by Roger, 2007.06.22. ++ // ++ write_nic_byte(dev, 0x0DB, (read_nic_byte(dev, 0x0DB)|(BIT2))); ++ write_nic_word(dev, 0x372, 0x59FA); // 0x4FFA-> 0x59FA. ++ write_nic_word(dev, 0x374, 0x59D2); // 0x4FD2-> 0x59D2. ++ write_nic_word(dev, 0x376, 0x59D2); ++ write_nic_word(dev, 0x378, 0x19FA); // 0x0FFA-> 0x19FA. ++ write_nic_word(dev, 0x37A, 0x19FA); // 0x0FFA-> 0x19FA. ++ write_nic_word(dev, 0x37C, 0x00D0); ++ ++ write_nic_byte(dev, 0x061, 0x00); ++ ++ // MAC. ++ write_nic_byte(dev, 0x180, 0x0F); ++ write_nic_byte(dev, 0x183, 0x03); ++ // 061218, lanhsin: for victorh request ++ write_nic_byte(dev, 0x0DA, 0x10); ++ //} ++ ++ // ++ // 061213, rcnjko: ++ // Set MAC.0x24D to 0x00 to prevent cts-to-self Tx/Rx stall symptom. ++ // If we set MAC 0x24D to 0x08, OFDM and CCK will turn off ++ // if not in use, and there is a bug about this action when ++ // we try to send CCK CTS and OFDM data together. ++ // ++ //PlatformEFIOWrite1Byte(Adapter, 0x24D, 0x00); ++ // 061218, lanhsin: for victorh request ++ write_nic_byte(dev, 0x24D, 0x08); ++ ++ // ++ // 061215, rcnjko: ++ // Follow SD3 RTL8185B_87B_MacPhy_Register.doc v0.4. ++ // ++ write_nic_dword(dev, HSSI_PARA, 0x0600321B); ++ // ++ // 061226, rcnjko: ++ // Babble found in HCT 2c_simultaneous test, server with 87B might ++ // receive a packet size about 2xxx bytes. ++ // So, we restrict RMS to 2048 (0x800), while as IC default value is 0xC00. ++ // ++ write_nic_word(dev, RMS, 0x0800); ++ ++ /*****20070321 Resolve HW page bug on system logo test ++ u8 faketemp=read_nic_byte(dev, 0x50);*/ ++ } ++} ++ ++/* this configures registers for beacon tx and enables it via ++ * rtl8180_beacon_tx_enable(). rtl8180_beacon_tx_disable() might ++ * be used to stop beacon transmission ++ */ ++#if 0 ++void rtl8180_start_tx_beacon(struct net_device *dev) ++{ ++ int i; ++ struct r8180_priv *priv = (struct r8180_priv *)ieee80211_priv(dev); ++ u16 word; ++ DMESG("Enabling beacon TX"); ++ //write_nic_byte(dev, 0x42,0xe6);// TCR ++ //rtl8180_init_beacon(dev); ++ //set_nic_txring(dev); ++// rtl8180_prepare_beacon(dev); ++ rtl8180_irq_disable(dev); ++// rtl8180_beacon_tx_enable(dev); ++ rtl8180_set_mode(dev,EPROM_CMD_CONFIG); ++ //write_nic_byte(dev,0x9d,0x20); //DMA Poll ++ //write_nic_word(dev,0x7a,0); ++ //write_nic_word(dev,0x7a,0x8000); ++ ++ ++ word = read_nic_word(dev, BcnItv); ++ word &= ~BcnItv_BcnItv; // clear Bcn_Itv ++ write_nic_word(dev, BcnItv, word); ++ ++ write_nic_word(dev, AtimWnd, ++ read_nic_word(dev, AtimWnd) &~ AtimWnd_AtimWnd); ++ ++ word = read_nic_word(dev, BintrItv); ++ word &= ~BintrItv_BintrItv; ++ ++ //word |= priv->ieee80211->beacon_interval * ++ // ((priv->txbeaconcount > 1)?(priv->txbeaconcount-1):1); ++ // FIXME:FIXME check if correct ^^ worked with 0x3e8; ++ ++ write_nic_word(dev, BintrItv, word); ++ ++ //write_nic_word(dev,0x2e,0xe002); ++ //write_nic_dword(dev,0x30,0xb8c7832e); ++ for(i=0; i<ETH_ALEN; i++) ++ write_nic_byte(dev, BSSID+i, priv->ieee80211->beacon_cell_ssid[i]); ++ ++// rtl8180_update_msr(dev); ++ ++ ++ //write_nic_byte(dev,CONFIG4,3); /* !!!!!!!!!! */ ++ ++ rtl8180_set_mode(dev, EPROM_CMD_NORMAL); ++ ++ rtl8180_irq_enable(dev); ++ ++ /* VV !!!!!!!!!! VV*/ ++ /* ++ rtl8180_set_mode(dev,EPROM_CMD_CONFIG); ++ write_nic_byte(dev,0x9d,0x00); ++ rtl8180_set_mode(dev,EPROM_CMD_NORMAL); ++*/ ++} ++#endif ++/*************************************************************************** ++ -------------------------------NET STUFF--------------------------- ++***************************************************************************/ ++static struct net_device_stats *rtl8180_stats(struct net_device *dev) ++{ ++ struct r8180_priv *priv = ieee80211_priv(dev); ++ ++ return &priv->ieee80211->stats; ++} ++ ++int _rtl8180_up(struct net_device *dev) ++{ ++ struct r8180_priv *priv = ieee80211_priv(dev); ++ //int i; ++ ++ priv->driver_upping = 1; ++ priv->up=1; ++ ++#ifdef LED ++ if(priv->ieee80211->bHwRadioOff == false) ++ priv->ieee80211->ieee80211_led_contorl(dev,LED_CTL_POWER_ON); ++#endif ++ MgntActSet_RF_State(dev, eRfOn, RF_CHANGE_BY_SW); ++ ++ rtl8180_adapter_start(dev); ++ rtl8180_rx_enable(dev); ++ rtl8180_tx_enable(dev); ++//by amy for rate adaptive ++ timer_rate_adaptive((unsigned long)dev); ++//by amy for rate adaptive ++ ++#ifdef SW_ANTE_DIVERSITY ++ if(priv->bSwAntennaDiverity){ ++ //DMESG("SW Antenna Diversity Enable!"); ++ SwAntennaDiversityTimerCallback(dev); ++ } ++#endif ++ ++ ieee80211_softmac_start_protocol(priv->ieee80211); ++ ++//by amy for ps ++ watch_dog_adaptive((unsigned long)dev); ++//by amy for ps ++ ++ ieee80211_reset_queue(priv->ieee80211); ++ if(!netif_queue_stopped(dev)) ++ netif_start_queue(dev); ++ else ++ netif_wake_queue(dev); ++ ++#ifndef CONFIG_SOFT_BEACON ++ if(NIC_8187B == priv->card_8187) ++ rtl8187_rx_manage_initiate(dev); ++#endif ++ ++#ifdef _RTL8187_EXT_PATCH_ ++ if(priv->mshobj && priv->mshobj->ext_patch_rtl8180_up ) ++ priv->mshobj->ext_patch_rtl8180_up(priv->mshobj); ++#endif ++ ++ ++ priv->driver_upping = 0; ++ //DMESG("rtl8187_open process complete"); ++ return 0; ++} ++ ++ ++int rtl8180_open(struct net_device *dev) ++{ ++ struct r8180_priv *priv = ieee80211_priv(dev); ++ int ret; ++//changed by lizhaoming for power on/off ++ if(priv->ieee80211->bHwRadioOff == false){ ++ //DMESG("rtl8187_open process "); ++ down(&priv->wx_sem); ++ ret = rtl8180_up(dev); ++ up(&priv->wx_sem); ++ return ret; ++ }else{ ++ DMESG("rtl8187_open process failed because radio off"); ++ return -1; ++ } ++ ++} ++ ++ ++int rtl8180_up(struct net_device *dev) ++{ ++ struct r8180_priv *priv = ieee80211_priv(dev); ++ ++ if (priv->up == 1) return -1; ++ ++ return _rtl8180_up(dev); ++} ++ ++ ++int rtl8180_close(struct net_device *dev) ++{ ++ struct r8180_priv *priv = ieee80211_priv(dev); ++ int ret; ++ ++ if (priv->up == 0) return -1; ++ ++ down(&priv->wx_sem); ++ ++ //DMESG("rtl8187_close process"); ++ ret = rtl8180_down(dev); ++#ifdef LED ++ priv->ieee80211->ieee80211_led_contorl(dev,LED_CTL_POWER_OFF); ++#endif ++ up(&priv->wx_sem); ++ ++ return ret; ++ ++} ++ ++int rtl8180_down(struct net_device *dev) ++{ ++ struct r8180_priv *priv = ieee80211_priv(dev); ++ ++ if (priv->up == 0) return -1; ++ ++ priv->up=0; ++ ++/* FIXME */ ++ if (!netif_queue_stopped(dev)) ++ netif_stop_queue(dev); ++ ++ //DMESG("rtl8180_down process"); ++ rtl8180_rtx_disable(dev); ++ rtl8180_irq_disable(dev); ++//by amy for rate adaptive ++ del_timer_sync(&priv->rateadapter_timer); ++ cancel_delayed_work(&priv->ieee80211->rate_adapter_wq); ++//by amy for rate adaptive ++ del_timer_sync(&priv->watch_dog_timer); ++ cancel_delayed_work(&priv->ieee80211->watch_dog_wq); ++ cancel_delayed_work(&priv->ieee80211->hw_dig_wq); ++ cancel_delayed_work(&priv->ieee80211->tx_pw_wq); ++ ++#ifdef SW_ANTE_DIVERSITY ++ del_timer_sync(&priv->SwAntennaDiversityTimer); ++ cancel_delayed_work(&priv->ieee80211->SwAntennaWorkItem); ++#endif ++ ++ ieee80211_softmac_stop_protocol(priv->ieee80211); ++ MgntActSet_RF_State(dev, eRfOff, RF_CHANGE_BY_SW); ++ //amy,081212 ++ memset(&(priv->ieee80211->current_network),0,sizeof(struct ieee80211_network)); ++ return 0; ++} ++ ++bool SetZebraRFPowerState8187B(struct net_device *dev,RT_RF_POWER_STATE eRFPowerState); ++ ++void rtl8180_commit(struct net_device *dev) ++{ ++ struct r8180_priv *priv = ieee80211_priv(dev); ++ int i; ++ ++ if (priv->up == 0) return ; ++ printk("==========>%s()\n", __FUNCTION__); ++ ++ /* FIXME */ ++ if (!netif_queue_stopped(dev)) ++ netif_stop_queue(dev); ++ ++//by amy for rate adaptive ++ del_timer_sync(&priv->rateadapter_timer); ++ cancel_delayed_work(&priv->ieee80211->rate_adapter_wq); ++//by amy for rate adaptive ++ del_timer_sync(&priv->watch_dog_timer); ++ cancel_delayed_work(&priv->ieee80211->watch_dog_wq); ++ cancel_delayed_work(&priv->ieee80211->hw_dig_wq); ++ cancel_delayed_work(&priv->ieee80211->tx_pw_wq); ++ ++#ifdef SW_ANTE_DIVERSITY ++ del_timer_sync(&priv->SwAntennaDiversityTimer); ++ cancel_delayed_work(&priv->ieee80211->SwAntennaWorkItem); ++#endif ++ ieee80211_softmac_stop_protocol(priv->ieee80211); ++ ++#if 0 ++ if(priv->ieee80211->bHwRadioOff == false){ ++ MgntActSet_RF_State(dev, eRfOff, RF_CHANGE_BY_HW); ++ mdelay(10); ++ MgntActSet_RF_State(dev, eRfOn, RF_CHANGE_BY_HW); ++ } ++#endif ++ ++ rtl8180_irq_disable(dev); ++ rtl8180_rtx_disable(dev); ++ ++ //test pending bug, john 20070815 ++ //initialize tx_pending ++ for(i=0;i<0x10;i++) atomic_set(&(priv->tx_pending[i]), 0); ++ ++ _rtl8180_up(dev); ++ priv->commit = 0; ++} ++ ++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,20)) ++void rtl8180_restart(struct work_struct *work) ++{ ++ struct r8180_priv *priv = container_of(work, struct r8180_priv, reset_wq); ++ struct ieee80211_device* ieee = priv->ieee80211;//for commit crash ++ struct net_device *dev = ieee->dev;//for commit crash ++#else ++void rtl8180_restart(struct net_device *dev) ++{ ++ ++ struct r8180_priv *priv = ieee80211_priv(dev); ++#endif ++ ++ down(&priv->wx_sem); ++ ++ rtl8180_commit(dev); ++ ++ up(&priv->wx_sem); ++} ++ ++static void r8180_set_multicast(struct net_device *dev) ++{ ++ struct r8180_priv *priv = ieee80211_priv(dev); ++ short promisc; ++ ++ //down(&priv->wx_sem); ++ ++ /* FIXME FIXME */ ++ ++ promisc = (dev->flags & IFF_PROMISC) ? 1:0; ++ ++ if (promisc != priv->promisc) ++ // rtl8180_commit(dev); ++ ++ priv->promisc = promisc; ++ ++ //schedule_work(&priv->reset_wq); ++ //up(&priv->wx_sem); ++} ++ ++ ++int r8180_set_mac_adr(struct net_device *dev, void *mac) ++{ ++ struct r8180_priv *priv = ieee80211_priv(dev); ++ struct sockaddr *addr = mac; ++ ++ down(&priv->wx_sem); ++ ++ memcpy(dev->dev_addr, addr->sa_data, ETH_ALEN); ++ ++#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0)) ++ schedule_work(&priv->reset_wq); ++#else ++ schedule_task(&priv->reset_wq); ++#endif ++ up(&priv->wx_sem); ++ ++ return 0; ++} ++ ++struct ipw_param { ++ u32 cmd; ++ u8 sta_addr[ETH_ALEN]; ++ union { ++ struct { ++ u8 name; ++ u32 value; ++ } wpa_param; ++ struct { ++ u32 len; ++ u8 reserved[32]; ++ u8 data[0]; ++ } wpa_ie; ++ struct{ ++ u32 command; ++ u32 reason_code; ++ } mlme; ++ struct { ++ u8 alg[16]; ++ u8 set_tx; ++ u32 err; ++ u8 idx; ++ u8 seq[8]; ++ u16 key_len; ++ u8 key[0]; ++ } crypt; ++ ++ } u; ++}; ++ ++ ++/* based on ipw2200 driver */ ++int rtl8180_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) ++{ ++ struct r8180_priv *priv = (struct r8180_priv *)ieee80211_priv(dev); ++ struct iwreq *wrq = (struct iwreq *)rq; ++ int ret=-1; ++ ++#ifdef JOHN_TKIP ++ u8 broadcast_addr[6] = {0xff,0xff,0xff,0xff,0xff,0xff}; ++ ++ struct ieee80211_device *ieee = priv->ieee80211; ++ struct ipw_param *ipw = (struct ipw_param *)wrq->u.data.pointer; ++ u32 key[4]; ++ ++#endif ++ ++#ifdef _RTL8187_EXT_PATCH_ ++ if(priv->mshobj && (priv->ieee80211->iw_mode == priv->ieee80211->iw_ext_mode) && priv->mshobj->ext_patch_rtl8180_ioctl) ++ { ++ // DO NOT put the belowing function in critical section, due to it uses "spin lock" ++ if((ret = priv->mshobj->ext_patch_rtl8180_ioctl(dev, rq, cmd)) != -EOPNOTSUPP) ++ return ret; ++ } ++#endif ++ ++ down(&priv->wx_sem); ++ ++ switch (cmd) { ++ case RTL_IOCTL_WPA_SUPPLICANT: ++#ifdef JOHN_TKIP ++ ++//the following code is specified for ipw driver in wpa_supplicant ++ if( ((u32*)wrq->u.data.pointer)[0]==3 ){ ++ ++ ++ if( ((u32*)wrq->u.data.pointer)[7] && ++ ( ((u32*)wrq->u.data.pointer)[3]==0x504d4343 || ++ ((u32*)wrq->u.data.pointer)[3]==0x50494b54 )) {//50494b54 tkip and 504d4343 ccmp ++ ++ //enable HW security of TKIP and CCMP ++ write_nic_byte(dev, WPA_CONFIG, SCR_TxSecEnable | SCR_RxSecEnable ); ++ ++ //copy key from wpa_supplicant ioctl info ++ key[0] = ((u32*)wrq->u.data.pointer)[12]; ++ key[1] = ((u32*)wrq->u.data.pointer)[13]; ++ key[2] = ((u32*)wrq->u.data.pointer)[14]; ++ key[3] = ((u32*)wrq->u.data.pointer)[15]; ++ switch (ieee->pairwise_key_type){ ++ case KEY_TYPE_TKIP: ++ setKey( dev, ++ 0, //EntryNo ++ ipw->u.crypt.idx, //KeyIndex ++ KEY_TYPE_TKIP, //KeyType ++ (u8*)ieee->ap_mac_addr, //MacAddr ++ 0, //DefaultKey ++ key); //KeyContent ++ break; ++ ++ case KEY_TYPE_CCMP: ++ setKey( dev, ++ 0, //EntryNo ++ ipw->u.crypt.idx, //KeyIndex ++ KEY_TYPE_CCMP, //KeyType ++ (u8*)ieee->ap_mac_addr, //MacAddr ++ 0, //DefaultKey ++ key); //KeyContent ++ break ++; ++ default: ++ printk("error on key_type: %d\n", ieee->pairwise_key_type); ++ break; ++ } ++ } ++ ++ //group key for broadcast ++ if( ((u32*)wrq->u.data.pointer)[9] ) { ++ ++ key[0] = ((u32*)wrq->u.data.pointer)[12]; ++ key[1] = ((u32*)wrq->u.data.pointer)[13]; ++ key[2] = ((u32*)wrq->u.data.pointer)[14]; ++ key[3] = ((u32*)wrq->u.data.pointer)[15]; ++ ++ if( ((u32*)wrq->u.data.pointer)[3]==0x50494b54 ){//50494b54 is the ASCII code of TKIP in reversed order ++ setKey( dev, ++ 1, //EntryNo ++ ipw->u.crypt.idx,//KeyIndex ++ KEY_TYPE_TKIP, //KeyType ++ broadcast_addr, //MacAddr ++ 0, //DefaultKey ++ key); //KeyContent ++ } ++ else if( ((u32*)wrq->u.data.pointer)[3]==0x504d4343 ){//CCMP ++ setKey( dev, ++ 1, //EntryNo ++ ipw->u.crypt.idx,//KeyIndex ++ KEY_TYPE_CCMP, //KeyType ++ broadcast_addr, //MacAddr ++ 0, //DefaultKey ++ key); //KeyContent ++ } ++ else if( ((u32*)wrq->u.data.pointer)[3]==0x656e6f6e ){//none ++ //do nothing ++ } ++ else if( ((u32*)wrq->u.data.pointer)[3]==0x504557 ){//WEP ++ setKey( dev, ++ 1, //EntryNo ++ ipw->u.crypt.idx,//KeyIndex ++ KEY_TYPE_WEP40, //KeyType ++ broadcast_addr, //MacAddr ++ 0, //DefaultKey ++ key); //KeyContent ++ } ++ else printk("undefine group key type: %8x\n", ((u32*)wrq->u.data.pointer)[3]); ++ } ++ ++ } ++#endif /*JOHN_TKIP*/ ++ ++ ++#ifdef JOHN_HWSEC_DEBUG ++ { ++ int i; ++ //john's test 0711 ++ printk("@@ wrq->u pointer = "); ++ for(i=0;i<wrq->u.data.length;i++){ ++ if(i%10==0) printk("\n"); ++ printk( "%8x|", ((u32*)wrq->u.data.pointer)[i] ); ++ } ++ printk("\n"); ++ } ++#endif /*JOHN_HWSEC_DEBUG*/ ++ ret = ieee80211_wpa_supplicant_ioctl(priv->ieee80211, &wrq->u.data); ++ break; ++ ++ default: ++ ret = -EOPNOTSUPP; ++ break; ++ } ++ ++ up(&priv->wx_sem); ++ ++ return ret; ++} ++ ++ ++struct tx_desc { ++ ++#ifdef _LINUX_BYTEORDER_LITTLE_ENDIAN_H ++ ++ ++//dword 0 ++unsigned int tpktsize:12; ++unsigned int rsvd0:3; ++unsigned int no_encrypt:1; ++unsigned int splcp:1; ++unsigned int morefrag:1; ++unsigned int ctsen:1; ++unsigned int rtsrate:4; ++unsigned int rtsen:1; ++unsigned int txrate:4; ++unsigned int last:1; ++unsigned int first:1; ++unsigned int dmaok:1; ++unsigned int own:1; ++ ++//dword 1 ++unsigned short rtsdur; ++unsigned short length:15; ++unsigned short l_ext:1; ++ ++//dword 2 ++unsigned int bufaddr; ++ ++ ++//dword 3 ++unsigned short rxlen:12; ++unsigned short rsvd1:3; ++unsigned short miccal:1; ++unsigned short dur; ++ ++//dword 4 ++unsigned int nextdescaddr; ++ ++//dword 5 ++unsigned char rtsagc; ++unsigned char retrylimit; ++unsigned short rtdb:1; ++unsigned short noacm:1; ++unsigned short pifs:1; ++unsigned short rsvd2:4; ++unsigned short rtsratefallback:4; ++unsigned short ratefallback:5; ++ ++//dword 6 ++unsigned short delaybound; ++unsigned short rsvd3:4; ++unsigned short agc:8; ++unsigned short antenna:1; ++unsigned short spc:2; ++unsigned short rsvd4:1; ++ ++//dword 7 ++unsigned char len_adjust:2; ++unsigned char rsvd5:1; ++unsigned char tpcdesen:1; ++unsigned char tpcpolarity:2; ++unsigned char tpcen:1; ++unsigned char pten:1; ++ ++unsigned char bckey:6; ++unsigned char enbckey:1; ++unsigned char enpmpd:1; ++unsigned short fragqsz; ++ ++ ++#else ++ ++#error "please modify tx_desc to your own\n" ++ ++#endif ++ ++ ++} __attribute__((packed)); ++ ++struct rx_desc_rtl8187b { ++ ++#ifdef _LINUX_BYTEORDER_LITTLE_ENDIAN_H ++ ++//dword 0 ++unsigned int rxlen:12; ++unsigned int icv:1; ++unsigned int crc32:1; ++unsigned int pwrmgt:1; ++unsigned int res:1; ++unsigned int bar:1; ++unsigned int pam:1; ++unsigned int mar:1; ++unsigned int qos:1; ++unsigned int rxrate:4; ++unsigned int trsw:1; ++unsigned int splcp:1; ++unsigned int fovf:1; ++unsigned int dmafail:1; ++unsigned int last:1; ++unsigned int first:1; ++unsigned int eor:1; ++unsigned int own:1; ++ ++ ++//dword 1 ++unsigned int tsftl; ++ ++ ++//dword 2 ++unsigned int tsfth; ++ ++ ++//dword 3 ++unsigned char sq; ++unsigned char rssi:7; ++unsigned char antenna:1; ++ ++unsigned char agc; ++unsigned char decrypted:1; ++unsigned char wakeup:1; ++unsigned char shift:1; ++unsigned char rsvd0:5; ++ ++//dword 4 ++unsigned int num_mcsi:4; ++unsigned int snr_long2end:6; ++unsigned int cfo_bias:6; ++ ++int pwdb_g12:8; ++unsigned int fot:8; ++ ++ ++ ++ ++#else ++ ++#error "please modify tx_desc to your own\n" ++ ++#endif ++ ++}__attribute__((packed)); ++ ++ ++ ++struct rx_desc_rtl8187 { ++ ++#ifdef _LINUX_BYTEORDER_LITTLE_ENDIAN_H ++ ++//dword 0 ++unsigned int rxlen:12; ++unsigned int icv:1; ++unsigned int crc32:1; ++unsigned int pwrmgt:1; ++unsigned int res:1; ++unsigned int bar:1; ++unsigned int pam:1; ++unsigned int mar:1; ++unsigned int qos:1; ++unsigned int rxrate:4; ++unsigned int trsw:1; ++unsigned int splcp:1; ++unsigned int fovf:1; ++unsigned int dmafail:1; ++unsigned int last:1; ++unsigned int first:1; ++unsigned int eor:1; ++unsigned int own:1; ++ ++//dword 1 ++unsigned char sq; ++unsigned char rssi:7; ++unsigned char antenna:1; ++ ++unsigned char agc; ++unsigned char decrypted:1; ++unsigned char wakeup:1; ++unsigned char shift:1; ++unsigned char rsvd0:5; ++ ++//dword 2 ++unsigned int tsftl; ++ ++//dword 3 ++unsigned int tsfth; ++ ++ ++ ++#else ++ ++#error "please modify tx_desc to your own\n" ++ ++#endif ++ ++ ++}__attribute__((packed)); ++ ++ ++ ++union rx_desc { ++ ++struct rx_desc_rtl8187b desc_87b; ++struct rx_desc_rtl8187 desc_87; ++ ++}__attribute__((packed)); ++ ++// ++// Description: ++// Perform signal smoothing for dynamic mechanism. ++// This is different with PerformSignalSmoothing8187 in smoothing fomula. ++// No dramatic adjustion is apply because dynamic mechanism need some degree ++// of correctness. ++// 2007.01.23, by shien chang. ++// ++void PerformUndecoratedSignalSmoothing8187(struct net_device *dev, struct ieee80211_rx_stats *stats) ++{ ++ struct r8180_priv *priv = (struct r8180_priv *)ieee80211_priv(dev); ++ bool bCckRate = rtl8180_IsWirelessBMode(rtl8180_rate2rate(stats->rate)); ++ ++ if(NIC_8187 == priv->card_8187) { ++ if(priv->UndecoratedSmoothedSS >= 0) { ++ priv->UndecoratedSmoothedSS = ((priv->UndecoratedSmoothedSS * 50) + (stats->signalstrength * 11)) / 60; ++ }else{ ++ priv->UndecoratedSmoothedSS = stats->signalstrength; ++ } ++ } else { ++ // Determin the current packet is CCK rate, by Bruce, 2007-04-12. ++ priv->bCurCCKPkt = bCckRate; ++ ++ // Tesing for SD3 DZ, by Bruce, 2007-04-11. ++ if(priv->UndecoratedSmoothedSS >= 0) { ++ priv->UndecoratedSmoothedSS = ((priv->UndecoratedSmoothedSS * 5) + (stats->signalstrength * 10)) / 6; ++ }else{ ++ priv->UndecoratedSmoothedSS = stats->signalstrength * 10; ++ } ++ ++ // ++ // Bacause the AGC parameter is not exactly correct under high power (AGC saturation), we need to record the RSSI value to be ++ // referenced by DoRxHighPower. It is not necessary to record this value when this packet is sent by OFDM rate. ++ // Advised by SD3 DZ, by Bruce, 2007-04-12. ++ // ++ if(bCckRate){ ++ priv->CurCCKRSSI = stats->signal; ++ }else{ ++ priv->CurCCKRSSI = 0; ++ } ++ } ++ //printk("Sommthing SignalSterngth (%d) => UndecoratedSmoothedSS (%d)\n", stats->signalstrength, priv->UndecoratedSmoothedSS); ++} ++ ++#ifdef THOMAS_SKB ++void rtl8180_irq_rx_tasklet(struct r8180_priv *priv) ++{ ++ int status,len,flen; ++ ++#ifdef SW_ANTE_DIVERSITY ++ u8 Antenna = 0; ++#endif ++ u32 SignalStrength = 0; ++ u32 quality = 0; ++ bool bCckRate = false; ++ char RX_PWDB = 0; ++ long RecvSignalPower=0; ++ struct sk_buff *skb; ++ struct sk_buff *skb2;//skb for check out of memory ++ union rx_desc *desc; ++ //struct urb *rx_urb = priv->rxurb_task; ++ struct ieee80211_hdr *hdr;//by amy ++ u16 fc,type; ++ u8 bHwError=0,bCRC=0,bICV=0; ++ long SignalStrengthIndex = 0; ++ struct ieee80211_rx_stats stats = { ++ .signal = 0, ++ .noise = -98, ++ .rate = 0, ++ //.mac_time = jiffies, ++ .freq = IEEE80211_24GHZ_BAND, ++ }; ++ ++ int *prx_inx=&priv->rx_inx; ++ struct urb *rx_urb=priv->rx_urb[*prx_inx]; //changed by jackson ++ struct net_device *dev = (struct net_device*)rx_urb->context; ++ //DMESG("=====>RX %x ",rx_urb->status); ++ ++ skb = priv->pp_rxskb[*prx_inx]; ++ status = rx_urb->status; ++ skb2 = dev_alloc_skb(RX_URB_SIZE); ++ ++ if (skb2 == NULL){ ++ printk(KERN_ALERT "No Skb For RX!/n"); ++ //rx_urb->transfer_buffer = skb->data; ++ //priv->pp_rxskb[*prx_inx] = skb; ++ } else { ++ ++ if(status == 0) ++ { ++ if(NIC_8187B == priv->card_8187) ++ { ++ stats.nic_type = NIC_8187B; ++ len = rx_urb->actual_length; ++ len -= sizeof (struct rx_desc_rtl8187b); ++ desc = (union rx_desc *)(rx_urb->transfer_buffer + len); ++ flen = desc->desc_87b.rxlen ; ++ ++ if( flen <= rx_urb->actual_length){ ++#if 1 ++#ifdef SW_ANTE_DIVERSITY ++ Antenna = desc->desc_87b.antenna; ++#endif ++ stats.mac_time[0] = desc->desc_87b.tsftl; ++ stats.mac_time[1] = desc->desc_87b.tsfth; ++ ++ stats.signal = desc->desc_87b.rssi; ++ //stats.noise = desc->desc_87b.sq; ++ quality = desc->desc_87b.sq; ++ stats.rate = desc->desc_87b.rxrate; ++ bCckRate = rtl8180_IsWirelessBMode(rtl8180_rate2rate(stats.rate)); ++ ++ if(!bCckRate) { // OFDM rate. ++ if(desc->desc_87b.pwdb_g12 < -106) ++ SignalStrength = 0; ++ else ++ SignalStrength = desc->desc_87b.pwdb_g12 + 106; ++ RX_PWDB = (desc->desc_87b.pwdb_g12)/2 -42; ++ } else { // CCK rate. ++ if(desc->desc_87b.agc> 174) ++ SignalStrength = 0; ++ else ++ SignalStrength = 174 - desc->desc_87b.agc; ++ RX_PWDB = ((desc->desc_87b.agc)/2)*(-1) - 8; ++ } ++ ++ //lzm mod 081028 based on windows driver ++ //compensate SignalStrength when switch TR to SW controled ++ if(priv->TrSwitchState == TR_SW_TX) { ++ SignalStrength = SignalStrength + 54; ++ RX_PWDB = RX_PWDB + 27; ++ } ++ ++ if(SignalStrength > 100) ++ SignalStrength = 100; ++ SignalStrength = (SignalStrength * 70) / 100 + 30; ++ ++ if(SignalStrength > 50) ++ SignalStrength = SignalStrength + 10; ++ if(SignalStrength > 100) ++ SignalStrength = 100; ++ ++ RecvSignalPower = RX_PWDB; ++ //printk("SignalStrength = %d \n",SignalStrength); ++ bHwError = (desc->desc_87b.fovf | desc->desc_87b.icv | desc->desc_87b.crc32); ++ bCRC = desc->desc_87b.crc32; ++ bICV = desc->desc_87b.icv; ++ priv->wstats.qual.level = (u8)SignalStrength; ++ ++ if(!bCckRate){ ++ if (quality > 127) ++ quality = 0; ++ else if (quality <27) ++ quality = 100; ++ else ++ quality = 127 - quality; ++ } else { ++ if(quality > 64) ++ quality = 0; ++ else ++ quality = ((64-quality)*100)/64; ++ } ++ ++ ++ priv ->wstats.qual.qual = quality; ++ priv->wstats.qual.noise = 100 - priv ->wstats.qual.qual; ++ ++ stats.signalstrength = (u8)SignalStrength; ++ stats.signal = (u8)quality; ++ stats.noise = desc->desc_87b.snr_long2end; ++ ++ skb_put(skb,flen-4); ++ ++ priv->stats.rxok++; ++ //by amy ++ hdr = (struct ieee80211_hdr *)skb->data; ++ fc = le16_to_cpu(hdr->frame_ctl); ++ type = WLAN_FC_GET_TYPE(fc); ++ ++ if((IEEE80211_FTYPE_CTL != type) && ++ (eqMacAddr(priv->ieee80211->current_network.bssid, (fc & IEEE80211_FCTL_TODS)? hdr->addr1 : (fc & IEEE80211_FCTL_FROMDS )? hdr->addr2 : hdr->addr3)) && (!bHwError) && (!bCRC)&& (!bICV)) ++ { ++ // Perform signal smoothing for dynamic mechanism on demand. ++ // This is different with PerformSignalSmoothing8187 in smoothing fomula. ++ // No dramatic adjustion is apply because dynamic mechanism need some degree ++ // of correctness. 2007.01.23, by shien chang. ++ PerformUndecoratedSignalSmoothing8187(dev, &stats); ++ ++ //Update signal strength and realted into private RxStats for UI query. ++ SignalStrengthIndex = NetgearSignalStrengthTranslate(priv->LastSignalStrengthInPercent, priv->wstats.qual.level); ++ priv->LastSignalStrengthInPercent = SignalStrengthIndex; ++ priv->SignalStrength = TranslateToDbm8187((u8)SignalStrengthIndex); ++ priv->SignalQuality = (priv->SignalQuality*5+quality+5)/6; ++ priv->RecvSignalPower = (priv->RecvSignalPower * 5 + RecvSignalPower - 1) / 6; ++#ifdef SW_ANTE_DIVERSITY ++ priv->LastRxPktAntenna = Antenna ? 1:0; ++ SwAntennaDiversityRxOk8185(dev, SignalStrength); ++#endif ++ } ++ //by amy ++#endif ++ if(!ieee80211_rx(priv->ieee80211,skb, &stats)) { ++ dev_kfree_skb_any(skb); ++ } ++ }else { ++ priv->stats.rxurberr++; ++ printk("URB Error flen:%d actual_length:%d\n", flen , rx_urb->actual_length); ++ dev_kfree_skb_any(skb); ++ } ++ } else { ++ stats.nic_type = NIC_8187; ++ len = rx_urb->actual_length; ++ len -= sizeof (struct rx_desc_rtl8187); ++ desc = (union rx_desc *)(rx_urb->transfer_buffer + len); ++ flen = desc->desc_87.rxlen ; ++ ++ if(flen <= rx_urb->actual_length){ ++ stats.signal = desc->desc_87.rssi; ++ stats.noise = desc->desc_87.sq; ++ stats.rate = desc->desc_87.rxrate; ++ stats.mac_time[0] = desc->desc_87.tsftl; ++ stats.mac_time[1] = desc->desc_87.tsfth; ++ SignalStrength = (desc->desc_87.agc&0xfe) >> 1; ++ if( ((stats.rate <= 22) && (stats.rate != 12) && (stats.rate != 18)) || (stats.rate == 44) )//need to translate to real rate here ++ bCckRate= TRUE; ++ if (!bCckRate) ++ { ++ if (SignalStrength > 90) SignalStrength = 90; ++ else if (SignalStrength < 25) SignalStrength = 25; ++ SignalStrength = ((90 - SignalStrength)*100)/65; ++ } ++ else ++ { ++ if (SignalStrength >95) SignalStrength = 95; ++ else if (SignalStrength < 30) SignalStrength = 30; ++ SignalStrength = ((95 - SignalStrength)*100)/65; ++ } ++ stats.signalstrength = (u8)SignalStrength; ++ ++ skb_put(skb,flen-4); ++ ++ priv->stats.rxok++; ++ ++ if(!ieee80211_rx(priv->ieee80211,skb, &stats)) ++ dev_kfree_skb_any(skb); ++ ++ ++ }else { ++ priv->stats.rxurberr++; ++ printk("URB Error flen:%d actual_length:%d\n", flen , rx_urb->actual_length); ++ dev_kfree_skb_any(skb); ++ } ++ } ++ }else{ ++ ++ //printk("RX Status Error!\n"); ++ priv->stats.rxstaterr++; ++ priv->ieee80211->stats.rx_errors++; ++ dev_kfree_skb_any(skb); ++ ++ } ++ ++ rx_urb->transfer_buffer = skb2->data; ++ ++ priv->pp_rxskb[*prx_inx] = skb2; ++ } ++ ++ if(status != -ENOENT ){ ++ rtl8187_rx_urbsubmit(dev,rx_urb); ++ } else { ++ priv->pp_rxskb[*prx_inx] = NULL; ++ dev_kfree_skb_any(skb2); ++ //printk("RX process %d aborted due to explicit shutdown (%x)(%d)\n ", *prx_inx, status, status); ++ } ++ ++ if (*prx_inx == (MAX_RX_URB -1)) ++ *prx_inx = 0; ++ else ++ *prx_inx = *prx_inx + 1; ++} ++#endif ++ ++#ifdef THOMAS_TASKLET ++void rtl8180_irq_rx_tasklet_new(struct r8180_priv *priv){ ++ unsigned long flags; ++ while( atomic_read( &priv->irt_counter ) ){ ++ spin_lock_irqsave(&priv->irq_lock,flags);//added by thomas ++ rtl8180_irq_rx_tasklet(priv); ++ spin_unlock_irqrestore(&priv->irq_lock,flags);//added by thomas ++ if(atomic_read(&priv->irt_counter) >= 1) ++ atomic_dec( &priv->irt_counter ); ++ } ++} ++#endif ++/**************************************************************************** ++ ---------------------------- USB_STUFF--------------------------- ++*****************************************************************************/ ++ ++static const struct net_device_ops rtl8187_netdev_ops = { ++ .ndo_open = rtl8180_open, ++ .ndo_stop = rtl8180_close, ++ .ndo_tx_timeout = tx_timeout, ++ .ndo_do_ioctl = rtl8180_ioctl, ++ .ndo_set_multicast_list = r8180_set_multicast, ++ .ndo_set_mac_address = r8180_set_mac_adr, ++ .ndo_validate_addr = eth_validate_addr, ++ .ndo_change_mtu = eth_change_mtu, ++ .ndo_start_xmit = ieee80211_xmit, ++ .ndo_get_stats = rtl8180_stats, ++}; ++ ++#if LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0) ++static int __devinit rtl8187_usb_probe(struct usb_interface *intf, ++ const struct usb_device_id *id) ++#else ++static void * __devinit rtl8187_usb_probe(struct usb_device *udev, ++ unsigned int ifnum, ++ const struct usb_device_id *id) ++#endif ++{ ++ struct net_device *dev = NULL; ++ struct r8180_priv *priv= NULL; ++ ++ ++#if LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0) ++ struct usb_device *udev = interface_to_usbdev(intf); ++#endif ++ ++ dev = alloc_ieee80211(sizeof(struct r8180_priv)); ++#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,24) ++ SET_MODULE_OWNER(dev); ++#endif ++ ++#if LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0) ++ usb_set_intfdata(intf, dev); ++ SET_NETDEV_DEV(dev, &intf->dev); ++#endif ++ priv = ieee80211_priv(dev); ++#if LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0) ++ priv->ieee80211 = netdev_priv(dev); ++#else ++ priv->ieee80211 = (struct net_device *)dev->priv; ++#endif ++ priv->udev=udev; ++#ifdef CPU_64BIT ++ priv->usb_buf = kmalloc(0x200, GFP_KERNEL); ++ priv->usb_pool = dma_pool_create("rtl8187b", NULL, 64, 64, 0); ++#endif ++//lzm add for write time out test ++#ifdef DEBUG_RW_REGISTER ++ { ++ int reg_index = 0; ++ for(reg_index = 0; reg_index <= 199; reg_index++) ++ { ++ priv->write_read_registers[reg_index].address = 0; ++ priv->write_read_registers[reg_index].content = 0; ++ priv->write_read_registers[reg_index].flag = 0; ++ } ++ priv->write_read_register_index = 0; ++ } ++#endif ++ //init netdev_ops, added by falcon.... ++ dev->netdev_ops = &rtl8187_netdev_ops; ++ ++ dev->wireless_handlers = &r8180_wx_handlers_def; ++#if WIRELESS_EXT >= 12 ++#if WIRELESS_EXT < 17 ++ dev->get_wireless_stats = r8180_get_wireless_stats; ++#endif ++ dev->wireless_handlers = (struct iw_handler_def *) &r8180_wx_handlers_def; ++#endif ++ ++ dev->type=ARPHRD_ETHER; ++ dev->watchdog_timeo = HZ*3; //modified by john, 0805 ++ ++ if (dev_alloc_name(dev, ifname) < 0){ ++ DMESG("Oops: devname already taken! Trying wlan%%d...\n"); ++ ifname = "wlan%d"; ++ dev_alloc_name(dev, ifname); ++ } ++ ++ if(rtl8180_init(dev)!=0){ ++ DMESG("Initialization failed"); ++ goto fail; ++ } ++ ++ netif_carrier_off(dev); ++ netif_stop_queue(dev); ++ ++ register_netdev(dev); ++ ++ rtl8180_proc_init_one(dev); ++ ++ /* init rfkill */ ++ r8187b_rfkill_init(dev); ++ ++ DMESG("Driver probe completed"); ++#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0) ++ return dev; ++#else ++ return 0; ++#endif ++ ++ ++fail: ++ free_ieee80211(dev); ++ ++ DMESG("wlan driver load failed\n"); ++#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0) ++ return NULL; ++#else ++ return -ENODEV; ++#endif ++ ++} ++ ++#if LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0) ++static void __devexit rtl8187_usb_disconnect(struct usb_interface *intf) ++#else ++static void __devexit rtl8187_usb_disconnect(struct usb_device *udev, void *ptr) ++#endif ++{ ++ struct r8180_priv *priv = NULL; ++#if LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0) ++ struct net_device *dev = usb_get_intfdata(intf); ++#else ++ struct net_device *dev = (struct net_device *)ptr; ++#endif ++ if(dev){ ++ unregister_netdev(dev); ++ ++ priv=ieee80211_priv(dev); ++ ++ MgntActSet_RF_State(dev, eRfOff, RF_CHANGE_BY_SW); ++ ++#ifdef _RTL8187_EXT_PATCH_ ++ if(priv && priv->mshobj) ++ { ++ if(priv->mshobj->ext_patch_remove_proc) ++ priv->mshobj->ext_patch_remove_proc(priv); ++ priv->ieee80211->ext_patch_ieee80211_start_protocol = 0; ++ priv->ieee80211->ext_patch_ieee80211_stop_protocol = 0; ++ priv->ieee80211->ext_patch_ieee80211_probe_req_1 = 0; ++ priv->ieee80211->ext_patch_ieee80211_probe_req_2 = 0; ++ priv->ieee80211->ext_patch_ieee80211_association_req_1 = 0; ++ priv->ieee80211->ext_patch_ieee80211_association_req_2 = 0; ++ priv->ieee80211->ext_patch_ieee80211_assoc_resp_by_net_1 = 0; ++ priv->ieee80211->ext_patch_ieee80211_assoc_resp_by_net_2 = 0; ++ priv->ieee80211->ext_patch_ieee80211_rx_frame_softmac_on_auth =0; ++ priv->ieee80211->ext_patch_ieee80211_rx_frame_softmac_on_deauth =0; ++ priv->ieee80211->ext_patch_ieee80211_rx_frame_softmac_on_assoc_req = 0; ++ priv->ieee80211->ext_patch_ieee80211_rx_frame_softmac_on_assoc_rsp = 0; ++ priv->ieee80211->ext_patch_ieee80211_ext_stop_scan_wq_set_channel = 0; ++ priv->ieee80211->ext_patch_ieee80211_process_probe_response_1 = 0; ++ priv->ieee80211->ext_patch_ieee80211_rx_mgt_on_probe_req = 0; ++ priv->ieee80211->ext_patch_ieee80211_rx_mgt_update_expire = 0; ++ priv->ieee80211->ext_patch_ieee80211_rx_on_rx = 0; ++ priv->ieee80211->ext_patch_get_beacon_get_probersp = 0; ++ priv->ieee80211->ext_patch_ieee80211_xmit = 0; ++ priv->ieee80211->ext_patch_ieee80211_rx_frame_get_hdrlen = 0; ++ priv->ieee80211->ext_patch_ieee80211_rx_is_valid_framectl = 0; ++ priv->ieee80211->ext_patch_ieee80211_rx_process_dataframe = 0; ++ // priv->ieee80211->ext_patch_is_duplicate_packet = 0; ++ priv->ieee80211->ext_patch_ieee80211_softmac_xmit_get_rate = 0; ++ free_mshobj(&priv->mshobj); ++ } ++#endif // _RTL8187_EXT_PATCH_ ++ ++ rtl8180_proc_remove_one(dev); ++ ++ rtl8180_down(dev); ++ priv->rf_close(dev); ++ ++ //rtl8180_rtx_disable(dev); ++ rtl8187_usb_deleteendpoints(dev); ++#ifdef LED ++ DeInitSwLeds(dev); ++#endif ++ rtl8180_irq_disable(dev); ++ rtl8180_reset(dev); ++ mdelay(10); ++ ++ } ++ ++#ifdef CPU_64BIT ++ if(priv->usb_buf) ++ kfree(priv->usb_buf); ++ if(priv->usb_pool) { ++ dma_pool_destroy(priv->usb_pool); ++ priv->usb_pool = NULL; ++ } ++#endif ++ free_ieee80211(dev); ++ DMESG("wlan driver removed"); ++} ++ ++/* fun with the built-in ieee80211 stack... */ ++extern int ieee80211_crypto_init(void); ++extern void ieee80211_crypto_deinit(void); ++extern int ieee80211_crypto_tkip_init(void); ++extern void ieee80211_crypto_tkip_exit(void); ++extern int ieee80211_crypto_ccmp_init(void); ++extern void ieee80211_crypto_ccmp_exit(void); ++extern int ieee80211_crypto_wep_init(void); ++extern void ieee80211_crypto_wep_exit(void); ++ ++static int __init rtl8187_usb_module_init(void) ++{ ++ int ret; ++ ++ ret = ieee80211_crypto_init(); ++ if (ret) { ++ printk(KERN_ERR "ieee80211_crypto_init() failed %d\n", ret); ++ return ret; ++ } ++ ret = ieee80211_crypto_tkip_init(); ++ if (ret) { ++ printk(KERN_ERR "ieee80211_crypto_tkip_init() failed %d\n", ret); ++ return ret; ++ } ++ ret = ieee80211_crypto_ccmp_init(); ++ if (ret) { ++ printk(KERN_ERR "ieee80211_crypto_ccmp_init() failed %d\n", ret); ++ return ret; ++ } ++ ret = ieee80211_crypto_wep_init(); ++ if (ret) { ++ printk(KERN_ERR "ieee80211_crypto_wep_init() failed %d\n", ret); ++ return ret; ++ } ++ ++ printk("\nLinux kernel driver for RTL8187/RTL8187B based WLAN cards\n"); ++ printk("Copyright (c) 2004-2008, Realsil Wlan\n"); ++ DMESG("Initializing module"); ++ DMESG("Wireless extensions version %d", WIRELESS_EXT); ++ rtl8180_proc_module_init(); ++ return usb_register(&rtl8187_usb_driver); ++} ++ ++static void __exit rtl8187_usb_module_exit(void) ++{ ++ r8187b_rfkill_exit(); ++ usb_deregister(&rtl8187_usb_driver); ++ rtl8180_proc_module_remove(); ++ ieee80211_crypto_tkip_exit(); ++ ieee80211_crypto_ccmp_exit(); ++ ieee80211_crypto_wep_exit(); ++ ieee80211_crypto_deinit(); ++ ++ DMESG("Exiting\n"); ++} ++ ++ ++void rtl8180_try_wake_queue(struct net_device *dev, int pri) ++{ ++ unsigned long flags; ++ short enough_desc; ++ struct r8180_priv *priv = (struct r8180_priv *)ieee80211_priv(dev); ++ ++ spin_lock_irqsave(&priv->tx_lock,flags); ++ enough_desc = check_nic_enought_desc(dev,pri); ++ spin_unlock_irqrestore(&priv->tx_lock,flags); ++ ++ if(enough_desc) ++ ieee80211_wake_queue(priv->ieee80211); ++} ++ ++#ifdef JOHN_HWSEC ++void EnableHWSecurityConfig8187(struct net_device *dev) ++{ ++ u8 SECR_value = 0x0; ++ SECR_value = SCR_TxSecEnable | SCR_RxSecEnable; ++ { ++ write_nic_byte(dev, WPA_CONFIG, 0x7);//SECR_value | SCR_UseDK ); ++ } ++} ++ ++void setKey(struct net_device *dev, ++ u8 EntryNo, ++ u8 KeyIndex, ++ u16 KeyType, ++ u8 *MacAddr, ++ u8 DefaultKey, ++ u32 *KeyContent ) ++{ ++ u32 TargetCommand = 0; ++ u32 TargetContent = 0; ++ u16 usConfig = 0; ++ int i; ++ usConfig |= BIT15 | (KeyType<<2) | (DefaultKey<<5) | KeyIndex; ++ ++ ++ for(i=0 ; i<6 ; i++){ ++ TargetCommand = i+6*EntryNo; ++ TargetCommand |= BIT31|BIT16; ++ ++ if(i==0){//MAC|Config ++ TargetContent = (u32)(*(MacAddr+0)) << 16| ++ (u32)(*(MacAddr+1)) << 24| ++ (u32)usConfig; ++ ++ write_nic_dword(dev, WCAMI, TargetContent); ++ write_nic_dword(dev, RWCAM, TargetCommand); ++ //printk("setkey cam =%8x\n", read_cam(dev, i+6*EntryNo)); ++ } else if(i==1){//MAC ++ TargetContent = (u32)(*(MacAddr+2)) | ++ (u32)(*(MacAddr+3)) << 8| ++ (u32)(*(MacAddr+4)) << 16| ++ (u32)(*(MacAddr+5)) << 24; ++ write_nic_dword(dev, WCAMI, TargetContent); ++ write_nic_dword(dev, RWCAM, TargetCommand); ++ } else { //Key Material ++ write_nic_dword(dev, WCAMI, (u32)(*(KeyContent+i-2)) ); ++ write_nic_dword(dev, RWCAM, TargetCommand); ++ } ++ } ++ ++} ++#endif ++ ++/**************************************************************************** ++ --------------------------- RF power on/power off ----------------- ++*****************************************************************************/ ++ ++/* ++ * the interface for changing the rfkill state ++ * @dev: the device of r8187b ++ * @eRfPowerStateToSet: the state we need to change, ++ * eRfOn: power on ++ * eRfOff: power off ++ * ++ * This function should be called by the SCI interrupt handler when the ++ * KEY_WLAN event happen(or install to the notify function of the SCI ++ * interrupt) or called in the wifi_set function of the rfkill interface for ++ * user-space, and also, it can be called to initialize the wifi state, and ++ * called when suspend/resume. ++ */ ++ ++void r8187b_wifi_change_rfkill_state(struct net_device *dev, RT_RF_POWER_STATE eRfPowerStateToSet) ++{ ++ struct r8180_priv *priv = ieee80211_priv(dev); ++ ++ if (eRfPowerStateToSet == eRfOn) ++ priv->ieee80211->bHwRadioOff = false; ++ else ++ priv->ieee80211->bHwRadioOff = true; ++ ++#ifdef CONFIG_RADIO_DEBUG ++ DMESG("SCI interrupt Methord Will Turn Radio %s", ++ (priv->ieee80211->bHwRadioOff == true) ? "Off" : "On"); ++#endif ++ ++#ifdef LED //by lizhaoming ++ if (priv->ieee80211->bHwRadioOff) ++ priv->ieee80211->ieee80211_led_contorl(dev, LED_CTL_POWER_OFF); ++ else ++ priv->ieee80211->ieee80211_led_contorl(dev, LED_CTL_POWER_ON); ++#endif ++ ++ MgntActSet_RF_State(dev, eRfPowerStateToSet, RF_CHANGE_BY_HW); ++ ++ /* report the rfkill state to the user-space via uevent interface */ ++ r8187b_wifi_report_state(priv); ++} ++ ++/*************************************************************************** ++ ------------------- module init / exit stubs ---------------- ++****************************************************************************/ ++module_init(rtl8187_usb_module_init); ++module_exit(rtl8187_usb_module_exit); +diff -Nur linux-2.6.33/drivers/net/wireless/rtl8187b/r8187.h linux-lemote/drivers/net/wireless/rtl8187b/r8187.h +--- linux-2.6.33/drivers/net/wireless/rtl8187b/r8187.h 1970-01-01 01:00:00.000000000 +0100 ++++ linux-lemote/drivers/net/wireless/rtl8187b/r8187.h 2010-03-06 16:43:22.000000000 +0100 +@@ -0,0 +1,811 @@ ++/* ++ This is part of rtl8187 OpenSource driver. ++ Copyright (C) Andrea Merello 2004-2005 <andreamrl@tiscali.it> ++ Released under the terms of GPL (General Public Licence) ++ ++ Parts of this driver are based on the GPL part of the ++ official realtek driver ++ ++ Parts of this driver are based on the rtl8180 driver skeleton ++ from Patric Schenke & Andres Salomon ++ ++ Parts of this driver are based on the Intel Pro Wireless 2100 GPL driver ++ ++ We want to tanks the Authors of those projects and the Ndiswrapper ++ project Authors. ++*/ ++ ++#ifndef R8180H ++#define R8180H ++ ++ ++#define RTL8187_MODULE_NAME "rtl8187" ++#define DMESG(x,a...) printk(KERN_INFO RTL8187_MODULE_NAME ": " x "\n", ## a) ++#define DMESGW(x,a...) printk(KERN_WARNING RTL8187_MODULE_NAME ": WW:" x "\n", ## a) ++#define DMESGE(x,a...) printk(KERN_WARNING RTL8187_MODULE_NAME ": EE:" x "\n", ## a) ++ ++#include <linux/module.h> ++#include <linux/kernel.h> ++//#include <linux/config.h> ++#include <linux/init.h> ++#include <linux/ioport.h> ++#include <linux/sched.h> ++#include <linux/types.h> ++#include <linux/slab.h> ++#include <linux/netdevice.h> ++//#include <linux/pci.h> ++#include <linux/usb.h> ++#include <linux/etherdevice.h> ++#include <linux/delay.h> ++#include <linux/rtnetlink.h> //for rtnl_lock() ++#include <linux/wireless.h> ++#include <linux/timer.h> ++#include <linux/proc_fs.h> // Necessary because we use the proc fs ++#include <linux/if_arp.h> ++#include <linux/random.h> ++#include <linux/version.h> ++#include <asm/io.h> ++#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,27) ++#include <asm/semaphore.h> ++#endif ++#include "ieee80211/ieee80211.h" ++#ifdef _RTL8187_EXT_PATCH_ ++#include "msh_class.h" ++#endif ++#ifdef LED ++#include "r8187_led.h" ++#endif ++ ++//added for HW security, john.0629 ++#define FALSE 0 ++#define TRUE 1 ++#define MAX_KEY_LEN 61 ++#define KEY_BUF_SIZE 5 ++ ++#define BIT0 0x00000001 ++#define BIT1 0x00000002 ++#define BIT2 0x00000004 ++#define BIT3 0x00000008 ++#define BIT4 0x00000010 ++#define BIT5 0x00000020 ++#define BIT6 0x00000040 ++#define BIT7 0x00000080 ++#define BIT8 0x00000100 ++#define BIT9 0x00000200 ++#define BIT10 0x00000400 ++#define BIT11 0x00000800 ++#define BIT12 0x00001000 ++#define BIT13 0x00002000 ++#define BIT14 0x00004000 ++#define BIT15 0x00008000 ++#define BIT16 0x00010000 ++#define BIT17 0x00020000 ++#define BIT18 0x00040000 ++#define BIT19 0x00080000 ++#define BIT20 0x00100000 ++#define BIT21 0x00200000 ++#define BIT22 0x00400000 ++#define BIT23 0x00800000 ++#define BIT24 0x01000000 ++#define BIT25 0x02000000 ++#define BIT26 0x04000000 ++#define BIT27 0x08000000 ++#define BIT28 0x10000000 ++#define BIT29 0x20000000 ++#define BIT30 0x40000000 ++#define BIT31 0x80000000 ++ ++//8187B Security ++#define RWCAM 0xA0 // Software read/write CAM config ++#define WCAMI 0xA4 // Software write CAM input content ++#define RCAMO 0xA8 // Output value from CAM according to 0xa0 setting ++#define DCAM 0xAC // Debug CAM Interface ++#define SECR 0xB0 // Security configuration register ++#define AESMSK_FC 0xB2 // AES Mask register for frame control (0xB2~0xB3). Added by Annie, 2006-03-06. ++#define AESMSK_SC 0x1FC // AES Mask for Sequence Control (0x1FC~0X1FD). Added by Annie, 2006-03-06. ++#define AESMSK_QC 0x1CE // AES Mask register for QoS Control when computing AES MIC, default = 0x000F. (2 bytes) ++ ++#define AESMSK_FC_DEFAULT 0xC78F // default value of AES MASK for Frame Control Field. (2 bytes) ++#define AESMSK_SC_DEFAULT 0x000F // default value of AES MASK for Sequence Control Field. (2 bytes) ++#define AESMSK_QC_DEFAULT 0x000F // default value of AES MASK for QoS Control Field. (2 bytes) ++ ++#define CAM_CONTENT_COUNT 6 ++#define CFG_DEFAULT_KEY BIT5 ++#define CFG_VALID BIT15 ++ ++//---------------------------------------------------------------------------- ++// 8187B WPA Config Register (offset 0xb0, 1 byte) ++//---------------------------------------------------------------------------- ++#define SCR_UseDK 0x01 ++#define SCR_TxSecEnable 0x02 ++#define SCR_RxSecEnable 0x04 ++ ++//---------------------------------------------------------------------------- ++// 8187B CAM Config Setting (offset 0xb0, 1 byte) ++//---------------------------------------------------------------------------- ++#define CAM_VALID 0x8000 ++#define CAM_NOTVALID 0x0000 ++#define CAM_USEDK 0x0020 ++ ++ ++#define CAM_NONE 0x0 ++#define CAM_WEP40 0x01 ++#define CAM_TKIP 0x02 ++#define CAM_AES 0x04 ++#define CAM_WEP104 0x05 ++ ++ ++//#define CAM_SIZE 16 ++#define TOTAL_CAM_ENTRY 16 ++#define CAM_ENTRY_LEN_IN_DW 6 // 6, unit: in u4byte. Added by Annie, 2006-05-25. ++#define CAM_ENTRY_LEN_IN_BYTE (CAM_ENTRY_LEN_IN_DW*sizeof(u4Byte)) // 24, unit: in u1byte. Added by Annie, 2006-05-25. ++ ++#define CAM_CONFIG_USEDK 1 ++#define CAM_CONFIG_NO_USEDK 0 ++ ++#define CAM_WRITE 0x00010000 ++#define CAM_READ 0x00000000 ++#define CAM_POLLINIG 0x80000000 ++ ++//================================================================= ++//================================================================= ++ ++#define EPROM_93c46 0 ++#define EPROM_93c56 1 ++ ++#define DEFAULT_FRAG_THRESHOLD 2342U ++#define MIN_FRAG_THRESHOLD 256U ++#define DEFAULT_BEACONINTERVAL 0x64U ++#define DEFAULT_BEACON_ESSID "Rtl8187" ++ ++#define DEFAULT_SSID "" ++#define DEFAULT_RETRY_RTS 7 ++#define DEFAULT_RETRY_DATA 7 ++#define PRISM_HDR_SIZE 64 ++ ++typedef enum _WIRELESS_MODE { ++ WIRELESS_MODE_UNKNOWN = 0x00, ++ WIRELESS_MODE_A = 0x01, ++ WIRELESS_MODE_B = 0x02, ++ WIRELESS_MODE_G = 0x04, ++ WIRELESS_MODE_AUTO = 0x08, ++} WIRELESS_MODE; ++ ++typedef enum _TR_SWITCH_STATE{ ++ TR_HW_CONTROLLED = 0, ++ TR_SW_TX = 1, ++}TR_SWITCH_STATE, *PTR_SWITCH_STATE; ++ ++ ++#define RTL_IOCTL_WPA_SUPPLICANT SIOCIWFIRSTPRIV+30 ++ ++typedef struct buffer ++{ ++ struct buffer *next; ++ u32 *buf; ++ ++} buffer; ++ ++typedef struct rtl_reg_debug{ ++ unsigned int cmd; ++ struct { ++ unsigned char type; ++ unsigned char addr; ++ unsigned char page; ++ unsigned char length; ++ } head; ++ unsigned char buf[0xff]; ++}rtl_reg_debug; ++typedef struct _CHANNEL_LIST{ ++ u8 Channel[MAX_CHANNEL_NUMBER + 1]; ++ u8 Len; ++}CHANNEL_LIST, *PCHANNEL_LIST; ++ ++#define MAX_LD_SLOT_NUM 10 ++#define DEFAULT_SLOT_NUM 2 ++#define KEEP_ALIVE_INTERVAL 20 // in seconds. ++#define CHECK_FOR_HANG_PERIOD 2 //be equal to watchdog check time ++#define DEFAULT_KEEP_ALIVE_LEVEL 1 ++ ++typedef struct _link_detect_t ++{ ++ u32 RxFrameNum[MAX_LD_SLOT_NUM]; // number of Rx Frame / CheckForHang_period to determine link status ++ u16 SlotNum; // number of CheckForHang period to determine link status, default is 2 ++ u16 SlotIndex; ++ ++ u32 NumTxOkInPeriod; //number of packet transmitted during CheckForHang ++ u32 NumRxOkInPeriod; //number of packet received during CheckForHang ++ ++ u8 IdleCount; // (KEEP_ALIVE_INTERVAL / CHECK_FOR_HANG_PERIOD) ++ u32 LastNumTxUnicast; ++ u32 LastNumRxUnicast; ++ ++ bool bBusyTraffic; //when it is set to 1, UI cann't scan at will. ++}link_detect_t, *plink_detect_t; ++ ++#if 0 ++ ++typedef struct tx_pendingbuf ++{ ++ struct ieee80211_txb *txb; ++ short ispending; ++ short descfrag; ++} tx_pendigbuf; ++ ++#endif ++ ++typedef struct Stats ++{ ++ unsigned long txrdu; ++// unsigned long rxrdu; ++ //unsigned long rxnolast; ++ //unsigned long rxnodata; ++// unsigned long rxreset; ++// unsigned long rxwrkaround; ++// unsigned long rxnopointer; ++ unsigned long rxok; ++ unsigned long rxurberr; ++ unsigned long rxstaterr; ++ unsigned long txnperr; ++ unsigned long txnpdrop; ++ unsigned long txresumed; ++// unsigned long rxerr; ++// unsigned long rxoverflow; ++// unsigned long rxint; ++ unsigned long txnpokint; ++// unsigned long txhpokint; ++// unsigned long txhperr; ++// unsigned long ints; ++// unsigned long shints; ++ unsigned long txoverflow; ++// unsigned long rxdmafail; ++// unsigned long txbeacon; ++// unsigned long txbeaconerr; ++ unsigned long txlpokint; ++ unsigned long txlpdrop; ++ unsigned long txlperr; ++ unsigned long txbeokint; ++ unsigned long txbedrop; ++ unsigned long txbeerr; ++ unsigned long txbkokint; ++ unsigned long txbkdrop; ++ unsigned long txbkerr; ++ unsigned long txviokint; ++ unsigned long txvidrop; ++ unsigned long txvierr; ++ unsigned long txvookint; ++ unsigned long txvodrop; ++ unsigned long txvoerr; ++ unsigned long txbeaconokint; ++ unsigned long txbeacondrop; ++ unsigned long txbeaconerr; ++ unsigned long txmanageokint; ++ unsigned long txmanagedrop; ++ unsigned long txmanageerr; ++ unsigned long txdatapkt; ++} Stats; ++ ++typedef struct ChnlAccessSetting { ++ u16 SIFS_Timer; ++ u16 DIFS_Timer; ++ u16 SlotTimeTimer; ++ u16 EIFS_Timer; ++ u16 CWminIndex; ++ u16 CWmaxIndex; ++}*PCHANNEL_ACCESS_SETTING,CHANNEL_ACCESS_SETTING; ++ ++ ++typedef enum _RT_RF_POWER_STATE ++{ ++ eRfOn, ++ eRfSleep, ++ eRfOff ++}RT_RF_POWER_STATE; ++typedef enum _RT_PS_MODE ++{ ++ eActive, // Active/Continuous access. ++ eMaxPs, // Max power save mode. ++ eFastPs // Fast power save mode. ++}RT_PS_MODE; ++// ++// Three wire mode. ++// ++#define IC_DEFAULT_THREE_WIRE 0 ++#define SW_THREE_WIRE 1 ++//RTL818xB ++#define SW_THREE_WIRE_BY_8051 2 ++#define HW_THREE_WIRE 3 ++#define HW_THREE_WIRE_BY_8051 4 ++//lzm add for write time out test ++typedef struct write_read_register ++{ ++ u32 address; ++ u32 content; ++ u32 flag; ++} write_read_register; ++//lzm add for write time out test ++typedef struct r8180_priv ++{ ++//lzm add for write time out test ++ struct write_read_register write_read_registers[200]; ++ u8 write_read_register_index; ++//lzm add for write time out test ++ ++ struct usb_device *udev; ++ short epromtype; ++ int irq; ++ struct ieee80211_device *ieee80211; ++ ++ short card_8187; /* O: rtl8180, 1:rtl8185 V B/C, 2:rtl8185 V D */ ++ short card_8187_Bversion; /* if TCR reports card V B/C this discriminates */ ++ short phy_ver; /* meaningful for rtl8225 1:A 2:B 3:C */ ++ short enable_gpio0; ++ enum card_type {PCI,MINIPCI,CARDBUS,USB/*rtl8187*/}card_type; ++ short hw_plcp_len; ++ short plcp_preamble_mode; ++ ++ spinlock_t irq_lock; ++// spinlock_t irq_th_lock; ++ spinlock_t tx_lock; ++//by amy for ps ++ spinlock_t rf_ps_lock; ++//by amy for ps ++ ++ u16 irq_mask; ++// short irq_enabled; ++ struct net_device *dev; ++ short chan; ++ short sens; ++ short max_sens; ++ u8 chtxpwr[15]; //channels from 1 to 14, 0 not used ++ u8 chtxpwr_ofdm[15]; //channels from 1 to 14, 0 not used ++ u8 cck_txpwr_base; ++ u8 ofdm_txpwr_base; ++ u8 challow[15]; //channels from 1 to 14, 0 not used ++ short up; ++ short crcmon; //if 1 allow bad crc frame reception in monitor mode ++// short prism_hdr; ++ ++// struct timer_list scan_timer; ++ /*short scanpending; ++ short stopscan;*/ ++// spinlock_t scan_lock; ++// u8 active_probe; ++ //u8 active_scan_num; ++ struct semaphore wx_sem; ++ struct semaphore set_chan_sem; ++// short hw_wep; ++ ++// short digphy; ++// short antb; ++// short diversity; ++// u8 cs_treshold; ++// short rcr_csense; ++ short rf_chip; ++// u32 key0[4]; ++ short (*rf_set_sens)(struct net_device *dev,short sens); ++ void (*rf_set_chan)(struct net_device *dev,short ch); ++ void (*rf_close)(struct net_device *dev); ++ void (*rf_init)(struct net_device *dev); ++ //short rate; ++ short promisc; ++ /*stats*/ ++ struct Stats stats; ++ struct _link_detect_t link_detect; //added on 1016.2008 ++ struct iw_statistics wstats; ++ struct proc_dir_entry *dir_dev; ++ ++ /*RX stuff*/ ++// u32 *rxring; ++// u32 *rxringtail; ++// dma_addr_t rxringdma; ++ struct urb **rx_urb; ++#ifdef THOMAS_BEACON ++ unsigned long *oldaddr; //lzm for 64bit CPU crash ++#endif ++ ++#ifdef THOMAS_TASKLET ++ atomic_t irt_counter;//count for irq_rx_tasklet ++#endif ++#ifdef JACKSON_NEW_RX ++ struct sk_buff **pp_rxskb; ++ int rx_inx; ++#endif ++ ++ short tx_urb_index; ++ ++ //struct buffer *rxbuffer; ++ //struct buffer *rxbufferhead; ++ //int rxringcount; ++ //u16 rxbuffersize; ++ ++ //struct sk_buff *rx_skb; ++ ++ //short rx_skb_complete; ++ ++ //u32 rx_prevlen; ++ //atomic_t tx_lp_pending; ++ //atomic_t tx_np_pending; ++ atomic_t tx_pending[0x10];//UART_PRIORITY+1 ++ ++#if 0 ++ /*TX stuff*/ ++ u32 *txlpring; ++ u32 *txhpring; ++ u32 *txnpring; ++ dma_addr_t txlpringdma; ++ dma_addr_t txhpringdma; ++ dma_addr_t txnpringdma; ++ u32 *txlpringtail; ++ u32 *txhpringtail; ++ u32 *txnpringtail; ++ u32 *txlpringhead; ++ u32 *txhpringhead; ++ u32 *txnpringhead; ++ struct buffer *txlpbufs; ++ struct buffer *txhpbufs; ++ struct buffer *txnpbufs; ++ struct buffer *txlpbufstail; ++ struct buffer *txhpbufstail; ++ struct buffer *txnpbufstail; ++ int txringcount; ++ int txbuffsize; ++ ++ //struct tx_pendingbuf txnp_pending; ++ struct tasklet_struct irq_tx_tasklet; ++#endif ++ struct tasklet_struct irq_rx_tasklet; ++ struct urb *rxurb_task; ++// u8 dma_poll_mask; ++ //short tx_suspend; ++ ++ /* adhoc/master mode stuff */ ++#if 0 ++ u32 *txbeacontail; ++ dma_addr_t txbeaconringdma; ++ u32 *txbeaconring; ++ int txbeaconcount; ++#endif ++// struct ieee_tx_beacon *beacon_buf; ++ //char *master_essid; ++// dma_addr_t beacondmabuf; ++ //u16 master_beaconinterval; ++// u32 master_beaconsize; ++ //u16 beacon_interval; ++ ++ //2 Tx Related variables ++ u16 ShortRetryLimit; ++ u16 LongRetryLimit; ++ u32 TransmitConfig; ++ u8 RegCWinMin; // For turbo mode CW adaptive. Added by Annie, 2005-10-27. ++ ++ //2 Rx Related variables ++ u16 EarlyRxThreshold; ++ u32 ReceiveConfig; ++ u8 AcmControl; ++ ++ u8 RFProgType; ++ ++ u8 retry_data; ++ u8 retry_rts; ++ u16 rts; ++ ++//by amy ++ long LastSignalStrengthInPercent; ++ long SignalStrength; ++ long SignalQuality; ++ u8 antenna_flag; ++ bool flag_beacon; ++//by amy ++//by amy for rate adaptive ++ struct timer_list rateadapter_timer; ++ u16 LastRetryCnt; ++ u16 LastRetryRate; ++ unsigned long LastTxokCnt; ++ unsigned long LastRxokCnt; ++ u16 CurrRetryCnt; ++ long RecvSignalPower; ++ unsigned long LastTxOKBytes; ++ u8 LastFailTxRate; ++ long LastFailTxRateSS; ++ u8 FailTxRateCount; ++ u32 LastTxThroughput; ++ unsigned long txokbytestotal; ++ //for up rate ++ unsigned short bTryuping; ++ u8 CurrTxRate; //the rate before up ++ u16 CurrRetryRate; ++ u16 TryupingCount; ++ u8 TryDownCountLowData; ++ u8 TryupingCountNoData; ++ ++ u8 CurrentOperaRate; ++//by amy for rate adaptive ++//by amy for power save ++ struct timer_list watch_dog_timer; ++ bool bInactivePs; ++ bool bSwRfProcessing; ++ RT_RF_POWER_STATE eInactivePowerState; ++ RT_RF_POWER_STATE eRFPowerState; ++ u32 RfOffReason; ++ bool RFChangeInProgress; ++ bool bInHctTest; ++ bool SetRFPowerStateInProgress; ++ //u8 RFProgType; ++ bool bLeisurePs; ++ RT_PS_MODE dot11PowerSaveMode; ++ u32 NumRxOkInPeriod; ++ u32 NumTxOkInPeriod; ++ u8 RegThreeWireMode; ++ bool ps_mode; ++//by amy for power save ++//by amy for DIG ++ bool bDigMechanism; ++ bool bCCKThMechanism; ++ u8 InitialGain; ++ u8 StageCCKTh; ++ u8 RegBModeGainStage; ++ u8 RegDigOfdmFaUpTh; //added by david, 2008.3.6 ++ u8 DIG_NumberFallbackVote; ++ u8 DIG_NumberUpgradeVote; ++ u16 CCKUpperTh; ++ u16 CCKLowerTh; ++ u32 FalseAlarmRegValue; //added by david, 2008.3.6 ++//by amy for DIG ++//{ added by david for high power, 2008.3.11 ++ int UndecoratedSmoothedSS; ++ bool bRegHighPowerMechanism; ++ bool bToUpdateTxPwr; ++ u8 Z2HiPwrUpperTh; ++ u8 Z2HiPwrLowerTh; ++ u8 Z2RSSIHiPwrUpperTh; ++ u8 Z2RSSIHiPwrLowerTh; ++ // Current CCK RSSI value to determine CCK high power, asked by SD3 DZ, by Bruce, 2007-04-12. ++ u8 CurCCKRSSI; ++ bool bCurCCKPkt; ++ u32 wMacRegRfPinsOutput; ++ u32 wMacRegRfPinsSelect; ++ TR_SWITCH_STATE TrSwitchState; ++//} ++//{added by david for radio on/off ++ u8 radion; ++//} ++ struct ChnlAccessSetting ChannelAccessSetting; ++#if LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0) ++ struct work_struct reset_wq; ++#else ++ struct tq_struct reset_wq; ++#endif ++ ++#ifdef _RTL8187_EXT_PATCH_ ++ struct mshclass *mshobj; ++#endif ++ ++#ifdef LED ++ /* add for led controll */ ++ u8 EEPROMCustomerID; ++ RT_CID_TYPE CustomerID; ++ LED_8187 Gpio0Led; ++ LED_8187 SwLed0; ++ LED_8187 SwLed1; ++ u8 bEnableLedCtrl; ++ LED_STRATEGY_8187 LedStrategy; ++ u8 PsrValue; ++ struct work_struct Gpio0LedWorkItem; ++ struct work_struct SwLed0WorkItem; ++ struct work_struct SwLed1WorkItem; ++#endif ++ u8 driver_upping; ++#ifdef CPU_64BIT ++ u8 *usb_buf; ++ struct dma_pool *usb_pool; ++#endif ++ ++ ++#ifdef SW_ANTE_DIVERSITY ++ ++//#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,20) ++// struct delayed_work SwAntennaWorkItem; ++//#else ++// struct work_struct SwAntennaWorkItem; ++//#endif ++ ++ bool bAntennaDiversityTimerIssued; ++ short antb; ++ short diversity; ++ bool AutoloadFailFlag; ++ u16 EEPROMVersion; ++ u8 EEPROMAntennaDiversity; ++ u16 EEPROMCSThreshold; ++ u8 EEPROMDefaultAntennaB; ++ u8 EEPROMDigitalPhy; ++ u32 EEPROMCSMethod; ++ u8 EEPROMGEPRFOffState; ++ // For HW antenna diversity, added by Roger, 2008.01.30. ++ u32 AdMainAntennaRxOkCnt; // Main antenna Rx OK count. ++ u32 AdAuxAntennaRxOkCnt; // Aux antenna Rx OK count. ++ bool bHWAdSwitched; // TRUE if we has switched default antenna by HW evaluation. ++ u8 EEPROMSwAntennaDiversity; ++ bool EEPROMDefaultAntenna1; ++ u8 RegSwAntennaDiversityMechanism;// 0:default from EEPROM, 1: disable, 2: enable. ++ bool bSwAntennaDiverity; ++ u8 RegDefaultAntenna;// 0: default from EEPROM, 1: main, 2: aux. Added by Roger, 2007.11.05. ++ bool bDefaultAntenna1; ++ //long SignalStrength; ++ long Stats_SignalStrength; ++ //long LastSignalStrengthInPercent; // In percentange, used for smoothing, e.g. Moving Average. ++ //long SignalQuality; // in 0-100 index. ++ long Stats_SignalQuality; ++ //long RecvSignalPower; // in dBm. ++ long Stats_RecvSignalPower; ++ u8 LastRxPktAntenna; // +by amy 080312 Antenn which received the lasted packet. 0: Aux, 1:Main. Added by Roger, 2008.01.25. ++ u32 AdRxOkCnt; ++ long AdRxSignalStrength; // Rx signal strength for Antenna Diversity, which had been smoothing, its valid range is [0,100]. ++ u8 CurrAntennaIndex; // Index to current Antenna (both Tx and Rx). ++ u8 AdTickCount; // Times of SwAntennaDiversityTimer happened. ++ u8 AdCheckPeriod; // # of period SwAntennaDiversityTimer to check Rx signal strength for SW Antenna Diversity. ++ u8 AdMinCheckPeriod; // Min value of AdCheckPeriod. ++ u8 AdMaxCheckPeriod; // Max value of AdCheckPeriod. ++ long AdRxSsThreshold; // Signal strength threshold to switch antenna. ++ long AdMaxRxSsThreshold; // Max value of AdRxSsThreshold. ++ bool bAdSwitchedChecking; // TRUE if we shall shall check Rx signal strength for last time switching antenna. ++ long AdRxSsBeforeSwitched; // Rx signal strength before we swithed antenna. ++ struct timer_list SwAntennaDiversityTimer; ++#endif ++ u8 commit; ++ ++//#ifdef ENABLE_DOT11D ++ u8 channel_plan; ++//#endif ++ u8 EEPROMSelectNewGPIO; ++}r8180_priv; ++ ++// for rtl8187 ++// now mirging to rtl8187B ++/* ++typedef enum{ ++ LOW_PRIORITY = 0x02, ++ NORM_PRIORITY ++ } priority_t; ++*/ ++//for rtl8187B ++typedef enum{ ++ BULK_PRIORITY = 0x01, ++ //RSVD0, ++ //RSVD1, ++ LOW_PRIORITY, ++ NORM_PRIORITY, ++ VO_PRIORITY, ++ VI_PRIORITY, //0x05 ++ BE_PRIORITY, ++ BK_PRIORITY, ++ RSVD2, ++ RSVD3, ++ BEACON_PRIORITY, //0x0A ++ HIGH_PRIORITY, ++ MANAGE_PRIORITY, ++ RSVD4, ++ RSVD5, ++ UART_PRIORITY //0x0F ++} priority_t; ++ ++typedef enum{ ++ NIC_8187 = 1, ++ NIC_8187B ++ } nic_t; ++ ++ ++typedef u32 AC_CODING; ++#define AC0_BE 0 // ACI: 0x00 // Best Effort ++#define AC1_BK 1 // ACI: 0x01 // Background ++#define AC2_VI 2 // ACI: 0x10 // Video ++#define AC3_VO 3 // ACI: 0x11 // Voice ++#define AC_MAX 4 // Max: define total number; Should not to be used as a real enum. ++ ++// ++// ECWmin/ECWmax field. ++// Ref: WMM spec 2.2.2: WME Parameter Element, p.13. ++// ++typedef union _ECW{ ++ u8 charData; ++ struct ++ { ++ u8 ECWmin:4; ++ u8 ECWmax:4; ++ }f; // Field ++}ECW, *PECW; ++ ++// ++// ACI/AIFSN Field. ++// Ref: WMM spec 2.2.2: WME Parameter Element, p.12. ++// ++typedef union _ACI_AIFSN{ ++ u8 charData; ++ ++ struct ++ { ++ u8 AIFSN:4; ++ u8 ACM:1; ++ u8 ACI:2; ++ u8 Reserved:1; ++ }f; // Field ++}ACI_AIFSN, *PACI_AIFSN; ++ ++// ++// AC Parameters Record Format. ++// Ref: WMM spec 2.2.2: WME Parameter Element, p.12. ++// ++typedef union _AC_PARAM{ ++ u32 longData; ++ u8 charData[4]; ++ ++ struct ++ { ++ ACI_AIFSN AciAifsn; ++ ECW Ecw; ++ u16 TXOPLimit; ++ }f; // Field ++}AC_PARAM, *PAC_PARAM; ++ ++#ifdef JOHN_HWSEC ++struct ssid_thread { ++ struct net_device *dev; ++ u8 name[IW_ESSID_MAX_SIZE + 1]; ++}; ++#endif ++ ++short rtl8180_tx(struct net_device *dev,u32* skbuf, int len,priority_t priority,short morefrag,short rate); ++ ++#ifdef JOHN_TKIP ++u32 read_cam(struct net_device *dev, u8 addr); ++void write_cam(struct net_device *dev, u8 addr, u32 data); ++#endif ++u8 read_nic_byte(struct net_device *dev, int x); ++u8 read_nic_byte_E(struct net_device *dev, int x); ++u32 read_nic_dword(struct net_device *dev, int x); ++u16 read_nic_word(struct net_device *dev, int x) ; ++void write_nic_byte(struct net_device *dev, int x,u8 y); ++void write_nic_byte_E(struct net_device *dev, int x,u8 y); ++void write_nic_word(struct net_device *dev, int x,u16 y); ++void write_nic_dword(struct net_device *dev, int x,u32 y); ++void force_pci_posting(struct net_device *dev); ++ ++void rtl8180_rtx_disable(struct net_device *); ++void rtl8180_rx_enable(struct net_device *); ++void rtl8180_tx_enable(struct net_device *); ++ ++void rtl8180_disassociate(struct net_device *dev); ++//void fix_rx_fifo(struct net_device *dev); ++void rtl8185_set_rf_pins_enable(struct net_device *dev,u32 a); ++ ++void rtl8180_set_anaparam(struct net_device *dev,u32 a); ++void rtl8185_set_anaparam2(struct net_device *dev,u32 a); ++void rtl8180_update_msr(struct net_device *dev); ++int rtl8180_down(struct net_device *dev); ++int rtl8180_up(struct net_device *dev); ++void rtl8180_commit(struct net_device *dev); ++void rtl8180_set_chan(struct net_device *dev,short ch); ++void write_phy(struct net_device *dev, u8 adr, u8 data); ++void write_phy_cck(struct net_device *dev, u8 adr, u32 data); ++void write_phy_ofdm(struct net_device *dev, u8 adr, u32 data); ++void rtl8185_tx_antenna(struct net_device *dev, u8 ant); ++void rtl8187_set_rxconf(struct net_device *dev); ++bool MgntActSet_RF_State(struct net_device *dev,RT_RF_POWER_STATE StateToSet,u32 ChangeSource); ++void IPSEnter(struct net_device *dev); ++void IPSLeave(struct net_device *dev); ++int r8187b_rfkill_init(struct net_device *dev); ++void r8187b_rfkill_exit(void); ++int r8187b_wifi_report_state(r8180_priv *priv); ++void r8187b_wifi_change_rfkill_state(struct net_device *dev, RT_RF_POWER_STATE eRfPowerStateToSet); ++bool SetRFPowerState(struct net_device *dev,RT_RF_POWER_STATE eRFPowerState); ++void rtl8180_patch_ieee80211_wx_sync_scan_wq(struct ieee80211_device *ieee); ++#ifdef _RTL8187_EXT_PATCH_ ++extern int r8180_wx_set_channel(struct net_device *dev, struct iw_request_info *info, union iwreq_data *wrqu, char *extra); ++#endif ++#ifdef JOHN_TKIP ++void EnableHWSecurityConfig8187(struct net_device *dev); ++void setKey(struct net_device *dev, u8 EntryNo, u8 KeyIndex, u16 KeyType, u8 *MacAddr, u8 DefaultKey, u32 *KeyContent ); ++ ++#endif ++ ++#endif +diff -Nur linux-2.6.33/drivers/net/wireless/rtl8187b/r8187_led.c linux-lemote/drivers/net/wireless/rtl8187b/r8187_led.c +--- linux-2.6.33/drivers/net/wireless/rtl8187b/r8187_led.c 1970-01-01 01:00:00.000000000 +0100 ++++ linux-lemote/drivers/net/wireless/rtl8187b/r8187_led.c 2010-03-06 16:43:22.000000000 +0100 +@@ -0,0 +1,1629 @@ ++/*++ ++Copyright (c) Realtek Semiconductor Corp. All rights reserved. ++ ++Module Name: ++ r8187_led.c ++ ++Abstract: ++ RTL8187 LED control functions ++ ++Major Change History: ++ When Who What ++ ---------- --------------- ------------------------------- ++ 2006-09-07 Xiong Created ++ ++Notes: ++ ++--*/ ++ ++/*--------------------------Include File------------------------------------*/ ++#include "ieee80211/ieee80211.h" ++#include "r8180_hw.h" ++#include "r8187.h" ++#include "r8180_93cx6.h" ++#include "r8187_led.h" ++ ++/** ++* ++* Initialization function for Sw Leds controll. ++* ++* \param dev The net device for this driver. ++* \return void. ++* ++* Note: ++* ++*/ ++ ++void ++InitSwLeds( ++ struct net_device *dev ++ ) ++{ ++ ++ struct r8180_priv *priv = ieee80211_priv(dev); ++ u16 usValue; ++// printk("========>%s()\n", __FUNCTION__); ++ ++// priv->CustomerID = RT_CID_87B_DELL; //by lizhaoming for DELL 2008.6.3 ++ priv->CustomerID = RT_CID_DEFAULT; //just set to default now ++ priv->bEnableLedCtrl = 1; ++ priv->PsrValue = read_nic_byte(dev, PSR); ++ usValue = eprom_read(dev, EEPROM_SW_REVD_OFFSET >> 1); ++ priv->EEPROMCustomerID = (u8)( usValue & EEPROM_CID_MASK ); ++ DMESG("EEPROM Customer ID: %02X", priv->EEPROMCustomerID); ++ ++ if(priv->CustomerID == RT_CID_DEFAULT) ++ { // If we have not yet change priv->CustomerID in register, ++ // we initialzie it from that of EEPROM with proper translation, 2006.07.03, by rcnjko. ++ switch(priv->EEPROMCustomerID) ++ { ++ case EEPROM_CID_RSVD0: ++ case EEPROM_CID_RSVD1: ++ priv->CustomerID = RT_CID_DEFAULT; ++ break; ++ ++ case EEPROM_CID_ALPHA0: ++ priv->CustomerID = RT_CID_8187_ALPHA0; ++ break; ++ ++ case EEPROM_CID_SERCOMM_PS: ++ priv->CustomerID = RT_CID_8187_SERCOMM_PS; ++ break; ++ ++ case EEPROM_CID_HW_LED: ++ priv->CustomerID = RT_CID_8187_HW_LED; ++ break; ++ ++ case EEPROM_CID_QMI: ++ priv->CustomerID = RT_CID_87B_QMI; ++ break; ++ ++ case EEPROM_CID_DELL: ++ priv->CustomerID = RT_CID_87B_DELL; ++ break; ++ ++ default: ++ // Invalid value, so, we use default value instead. ++ priv->CustomerID = RT_CID_DEFAULT; ++ break; ++ } ++ } ++ switch(priv->CustomerID) ++ { ++ case RT_CID_DEFAULT: ++ priv->LedStrategy = SW_LED_MODE0; ++ break; ++ ++ case RT_CID_8187_ALPHA0: ++ priv->LedStrategy = SW_LED_MODE1; ++ break; ++ ++ case RT_CID_8187_SERCOMM_PS: ++ priv->LedStrategy = SW_LED_MODE3; ++ break; ++ ++ case RT_CID_87B_QMI: ++ priv->LedStrategy = SW_LED_MODE4; ++ break; ++ ++ case RT_CID_87B_DELL: ++ priv->LedStrategy = SW_LED_MODE5; ++ break; ++ ++ case RT_CID_8187_HW_LED: ++ priv->LedStrategy = HW_LED; ++ break; ++ ++ default: ++ priv->LedStrategy = SW_LED_MODE0; ++ break; ++ } ++ ++ InitLed8187(dev, ++ &(priv->Gpio0Led), ++ LED_PIN_GPIO0, ++ Gpio0LedBlinkTimerCallback); ++#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,20) ++ INIT_WORK(&priv->Gpio0LedWorkItem, ++ (void(*)(void*))Gpio0LedWorkItemCallback, dev); ++ ++ InitLed8187(dev, ++ &(priv->SwLed0), ++ LED_PIN_LED0, ++ SwLed0BlinkTimerCallback); ++ INIT_WORK(&priv->SwLed0WorkItem, ++ (void(*)(void*))SwLed0WorkItemCallback, dev); ++ ++ InitLed8187(dev, ++ &(priv->SwLed1), ++ LED_PIN_LED1, ++ SwLed1BlinkTimerCallback); ++ INIT_WORK(&priv->SwLed1WorkItem, ++ (void(*)(void*))SwLed1WorkItemCallback, dev); ++#else ++INIT_WORK(&priv->Gpio0LedWorkItem, ++ Gpio0LedWorkItemCallback); ++ ++ InitLed8187(dev, ++ &(priv->SwLed0), ++ LED_PIN_LED0, ++ SwLed0BlinkTimerCallback); ++ INIT_WORK(&priv->SwLed0WorkItem, ++ SwLed0WorkItemCallback); ++ ++ InitLed8187(dev, ++ &(priv->SwLed1), ++ LED_PIN_LED1, ++ SwLed1BlinkTimerCallback); ++ INIT_WORK(&priv->SwLed1WorkItem, ++ SwLed1WorkItemCallback); ++#endif ++} ++ ++void ++DeInitSwLeds( ++ struct net_device *dev ++ ) ++{ ++ struct r8180_priv *priv = ieee80211_priv(dev); ++ ++// printk("=========>%s In\n", __FUNCTION__); ++ DeInitLed8187(dev, &(priv->Gpio0Led)); ++ DeInitLed8187(dev, &(priv->SwLed0)); ++ DeInitLed8187(dev, &(priv->SwLed1)); ++} ++ ++void ++InitLed8187( ++ struct net_device *dev, ++ PLED_8187 pLed, ++ LED_PIN_8187 LedPin, ++ void * BlinkCallBackFunc) ++{ ++// printk("=========>%s In\n", __FUNCTION__); ++ pLed->LedPin = LedPin; ++ ++ pLed->bLedOn = 0; ++ pLed->CurrLedState = LED_OFF; ++ ++ pLed->bLedBlinkInProgress = 0; ++ pLed->BlinkTimes = 0; ++ pLed->BlinkingLedState = LED_OFF; ++ ++ init_timer(&(pLed->BlinkTimer)); ++ pLed->BlinkTimer.data = (unsigned long)dev; ++ pLed->BlinkTimer.function = BlinkCallBackFunc; ++ //PlatformInitializeTimer(dev, &(pLed->BlinkTimer), BlinkCallBackFunc); ++} ++ ++void ++DeInitLed8187( ++ struct net_device *dev, ++ PLED_8187 pLed) ++{ ++ //printk("=========>%s In\n", __FUNCTION__); ++ //PlatformCancelTimer(dev, &(pLed->BlinkTimer)); ++ del_timer_sync(&(pLed->BlinkTimer)); ++ // We should reset bLedBlinkInProgress if we cancel the LedControlTimer, 2005.03.10, by rcnjko. ++ pLed->bLedBlinkInProgress = 0; ++} ++ ++void ++LedControl8187( ++ struct net_device *dev, ++ LED_CTL_MODE LedAction ++) ++{ ++ struct r8180_priv *priv = ieee80211_priv(dev); ++// printk("=========>%s In\n", __FUNCTION__); ++ if( priv->bEnableLedCtrl == 0) ++ return; ++ ++ ++ if( priv->eRFPowerState != eRfOn && ++ (LedAction == LED_CTL_TX || LedAction == LED_CTL_RX || ++ LedAction == LED_CTL_SITE_SURVEY || ++ LedAction == LED_CTL_LINK || ++ LedAction == LED_CTL_NO_LINK) ) ++ { ++ return; ++ } ++ ++ ++ switch(priv->LedStrategy) ++ { ++ case SW_LED_MODE0: ++ SwLedControlMode0(dev, LedAction); ++ break; ++ ++ case SW_LED_MODE1: ++ SwLedControlMode1(dev, LedAction); ++ break; ++ ++ case SW_LED_MODE2: ++ SwLedControlMode2(dev, LedAction); ++ break; ++ ++ case SW_LED_MODE3: ++ SwLedControlMode3(dev, LedAction); ++ break; ++ case SW_LED_MODE4: ++ SwLedControlMode4(dev, LedAction); ++ break; ++ ++ case SW_LED_MODE5: ++ SwLedControlMode5(dev, LedAction); ++ break; ++ ++ default: ++ break; ++ } ++} ++ ++ ++// ++// Description: ++// Implement each led action for SW_LED_MODE0. ++// This is default strategy. ++// ++void ++SwLedControlMode0( ++ struct net_device *dev, ++ LED_CTL_MODE LedAction ++) ++{ ++ struct r8180_priv *priv = ieee80211_priv(dev); ++ PLED_8187 pLed = &(priv->Gpio0Led); ++ ++// printk("===+++++++++++++++======>%s In\n", __FUNCTION__); ++ // Decide led state ++ switch(LedAction) ++ { ++ case LED_CTL_TX: ++ case LED_CTL_RX: ++ if( pLed->bLedBlinkInProgress == 0 ) ++ { ++ pLed->CurrLedState = LED_BLINK_NORMAL; ++ pLed->BlinkTimes = 2; ++ // printk("===========>LED_CTL_TX/RX \n"); ++ } ++ else ++ { ++ return; ++ } ++ break; ++ ++ case LED_CTL_SITE_SURVEY: ++ if( pLed->bLedBlinkInProgress == 0 ) ++ { ++ pLed->CurrLedState = LED_BLINK_SLOWLY; ++ // pLed->BlinkTimes = 10; ++ //printk("===========>LED_CTL_SURVEY \n"); ++ } ++ else ++ { ++ return; ++ } ++ break; ++ ++ case LED_CTL_LINK: ++ // printk("===========>associate commplite LED_CTL_LINK\n"); ++ pLed->CurrLedState = LED_ON; ++ break; ++ ++ case LED_CTL_NO_LINK: ++ pLed->CurrLedState = LED_OFF; ++ break; ++ ++ case LED_CTL_POWER_ON: ++ // printk("===========>LED_CTL_POWER_ON\n"); ++ pLed->CurrLedState = LED_POWER_ON_BLINK; ++ break; ++ ++ case LED_CTL_POWER_OFF: ++ pLed->CurrLedState = LED_OFF; ++ break; ++ ++ default: ++ return; ++ break; ++ } ++ ++ // Change led state. ++ switch(pLed->CurrLedState) ++ { ++ case LED_ON: ++ if( pLed->bLedBlinkInProgress == 0 ) ++ { ++ SwLedOn(dev, pLed); ++ } ++ break; ++ ++ case LED_OFF://modified by lizhaoming 2008.6.23 ++ // if( pLed->bLedBlinkInProgress == 0 ) ++ // { ++ // SwLedOff(dev, pLed); ++ // } ++ ++ if(pLed->bLedBlinkInProgress )/////////lizhaoming ++ { ++ del_timer_sync(&(pLed->BlinkTimer)); ++ pLed->bLedBlinkInProgress = FALSE; ++ } ++ SwLedOff(dev, pLed); ++ break; ++ ++ case LED_BLINK_NORMAL: ++ if( pLed->bLedBlinkInProgress == 0 ) ++ { ++ pLed->bLedBlinkInProgress = 1; ++ if( pLed->bLedOn ) ++ pLed->BlinkingLedState = LED_OFF; ++ else ++ pLed->BlinkingLedState = LED_ON; ++ ++ //pLed->BlinkTimer.expires = jiffies + LED_BLINK_NORMAL_INTERVAL; ++ //add_timer(&(pLed->BlinkTimer)); ++ mod_timer(&pLed->BlinkTimer, jiffies + MSECS(LED_BLINK_NORMAL_INTERVAL)); ++ //PlatformSetTimer(dev, &(pLed->BlinkTimer), LED_BLINK_NORMAL_INTERVAL); ++ } ++ break; ++ ++ case LED_BLINK_SLOWLY: ++ if( pLed->bLedBlinkInProgress == 0 ) ++ { ++ //printk("=======>%s SLOWLY\n", __func__); ++ pLed->bLedBlinkInProgress = 1; ++ // if( pLed->bLedOn ) ++ pLed->BlinkingLedState = LED_OFF;//for LED_SHIN is LED on ++ // else ++ // pLed->BlinkingLedState = LED_ON; ++ ++ mod_timer(&pLed->BlinkTimer, jiffies + MSECS(LED_BLINK_SLOWLY_INTERVAL)); ++ } ++ break; ++ ++ case LED_POWER_ON_BLINK: ++ SwLedOn(dev, pLed); ++#ifdef LED_SHIN ++ mdelay(100); ++ SwLedOff(dev, pLed); ++#endif ++ break; ++ ++ default: ++ break; ++ } ++} ++ ++// ++// Description: ++// Implement each led action for SW_LED_MODE1. ++// For example, this is applied by ALPHA. ++// ++void ++SwLedControlMode1( ++ struct net_device *dev, ++ LED_CTL_MODE LedAction ++) ++{ ++ struct r8180_priv *priv = ieee80211_priv(dev); ++ PLED_8187 pLed0 = &(priv->SwLed0); ++ PLED_8187 pLed1 = &(priv->SwLed1); ++// printk("=====++++++++++++++++++++++====>%s In\n", __FUNCTION__); ++ ++ switch(LedAction) ++ { ++ case LED_CTL_TX: ++ if( pLed0->bLedBlinkInProgress == 0 ) ++ { ++ pLed0->CurrLedState = LED_BLINK_NORMAL; ++ pLed0->BlinkTimes = 2; ++ pLed0->bLedBlinkInProgress = 1; ++ if( pLed0->bLedOn ) ++ pLed0->BlinkingLedState = LED_OFF; ++ else ++ pLed0->BlinkingLedState = LED_ON; ++ ++ //pLed0->BlinkTimer.expires = jiffies + LED_BLINK_NORMAL_INTERVAL; ++ //add_timer(&(pLed0->BlinkTimer)); ++ mod_timer(&pLed0->BlinkTimer, jiffies + MSECS(LED_BLINK_NORMAL_INTERVAL)); ++ //PlatformSetTimer(dev, &(pLed0->BlinkTimer), LED_BLINK_NORMAL_INTERVAL); ++ } ++ break; ++ ++ case LED_CTL_LINK: ++ pLed0->CurrLedState = LED_ON; ++ if( pLed0->bLedBlinkInProgress == 0 ) ++ { ++ SwLedOn(dev, pLed0); ++ } ++ break; ++ ++ case LED_CTL_NO_LINK: ++ pLed0->CurrLedState = LED_OFF; ++ if( pLed0->bLedBlinkInProgress == 0 ) ++ { ++ SwLedOff(dev, pLed0); ++ } ++ break; ++ ++ case LED_CTL_POWER_ON: ++ pLed0->CurrLedState = LED_OFF; ++ SwLedOff(dev, pLed0); ++ ++ pLed1->CurrLedState = LED_ON; ++ SwLedOn(dev, pLed1); ++ ++ break; ++ ++ case LED_CTL_POWER_OFF: ++ pLed0->CurrLedState = LED_OFF; ++ SwLedOff(dev, pLed0); ++ ++ pLed1->CurrLedState = LED_OFF; ++ SwLedOff(dev, pLed1); ++ break; ++ ++ case LED_CTL_SITE_SURVEY: ++ if( pLed0->bLedBlinkInProgress == 0 ) ++ { ++ pLed0->CurrLedState = LED_BLINK_SLOWLY;; ++ pLed0->BlinkTimes = 10; ++ pLed0->bLedBlinkInProgress = 1; ++ if( pLed0->bLedOn ) ++ pLed0->BlinkingLedState = LED_OFF; ++ else ++ pLed0->BlinkingLedState = LED_ON; ++ ++ //pLed0->BlinkTimer.expires = jiffies + LED_BLINK_SLOWLY_INTERVAL; ++ //add_timer(&(pLed0->BlinkTimer)); ++ mod_timer(&pLed0->BlinkTimer, jiffies + MSECS(LED_BLINK_SLOWLY_INTERVAL)); ++ //PlatformSetTimer(dev, &(pLed0->BlinkTimer), LED_BLINK_SLOWLY_INTERVAL); ++ } ++ break; ++ ++ default: ++ break; ++ } ++} ++ ++// ++// Description: ++// Implement each led action for SW_LED_MODE2, ++// which is customized for AzWave 8187 minicard. ++// 2006.04.03, by rcnjko. ++// ++void ++SwLedControlMode2( ++ struct net_device *dev, ++ LED_CTL_MODE LedAction ++) ++{ ++ struct r8180_priv *priv = ieee80211_priv(dev); ++ PLED_8187 pLed = &(priv->Gpio0Led); ++ ++// printk("====+++++++++++++++++++++=====>%s In\n", __FUNCTION__); ++ // Decide led state ++ switch(LedAction) ++ { ++ case LED_CTL_TX: ++ case LED_CTL_RX: ++ if( pLed->bLedBlinkInProgress == 0 ) ++ { ++ pLed->bLedBlinkInProgress = 1; ++ ++ pLed->CurrLedState = LED_BLINK_NORMAL; ++ pLed->BlinkTimes = 2; ++ ++ if( pLed->bLedOn ) ++ pLed->BlinkingLedState = LED_OFF; ++ else ++ pLed->BlinkingLedState = LED_ON; ++ ++ //pLed->BlinkTimer.expires = jiffies + LED_BLINK_NORMAL_INTERVAL; ++ //add_timer(&(pLed->BlinkTimer)); ++ mod_timer(&pLed->BlinkTimer, jiffies + MSECS(LED_BLINK_NORMAL_INTERVAL)); ++ //PlatformSetTimer(dev, &(pLed->BlinkTimer), LED_BLINK_NORMAL_INTERVAL); ++ } ++ break; ++ ++ case LED_CTL_SITE_SURVEY: ++ if( pLed->bLedBlinkInProgress == 0 ) ++ { ++ pLed->bLedBlinkInProgress = 1; ++ ++ //if( dev->MgntInfo.mAssoc || ++ // dev->MgntInfo.mIbss ) ++ //{ ++ pLed->CurrLedState = LED_SCAN_BLINK; ++ pLed->BlinkTimes = 4; ++ //} ++ //else ++ //{ ++ // pLed->CurrLedState = LED_NO_LINK_BLINK; ++ // pLed->BlinkTimes = 24; ++ //} ++ ++ if( pLed->bLedOn ) ++ { ++ pLed->BlinkingLedState = LED_OFF; ++ //pLed->BlinkTimer.expires = jiffies + LED_CM2_BLINK_ON_INTERVAL; ++ //add_timer(&(pLed->BlinkTimer)); ++ mod_timer(&pLed->BlinkTimer, jiffies + MSECS(LED_CM2_BLINK_ON_INTERVAL)); ++ //PlatformSetTimer(dev, &(pLed->BlinkTimer), LED_CM2_BLINK_ON_INTERVAL); ++ } ++ else ++ { ++ pLed->BlinkingLedState = LED_ON; ++ //pLed->BlinkTimer.expires = jiffies + LED_CM2_BLINK_OFF_INTERVAL; ++ //add_timer(&(pLed->BlinkTimer)); ++ mod_timer(&pLed->BlinkTimer, jiffies + MSECS(LED_CM2_BLINK_OFF_INTERVAL)); ++ //PlatformSetTimer(dev, &(pLed->BlinkTimer), LED_CM2_BLINK_OFF_INTERVAL); ++ } ++ } ++ else ++ { ++ if(pLed->CurrLedState != LED_NO_LINK_BLINK) ++ { ++ pLed->CurrLedState = LED_SCAN_BLINK; ++ /* ++ if( dev->MgntInfo.mAssoc || ++ dev->MgntInfo.mIbss ) ++ { ++ pLed->CurrLedState = LED_SCAN_BLINK; ++ } ++ else ++ { ++ pLed->CurrLedState = LED_NO_LINK_BLINK; ++ } ++ */ ++ } ++ } ++ break; ++ ++ case LED_CTL_NO_LINK: ++ if( pLed->bLedBlinkInProgress == 0 ) ++ { ++ pLed->bLedBlinkInProgress = 1; ++ ++ pLed->CurrLedState = LED_NO_LINK_BLINK; ++ pLed->BlinkTimes = 24; ++ ++ if( pLed->bLedOn ) ++ { ++ pLed->BlinkingLedState = LED_OFF; ++ //pLed->BlinkTimer.expires = jiffies + LED_CM2_BLINK_ON_INTERVAL; ++ //add_timer(&(pLed->BlinkTimer)); ++ mod_timer(&pLed->BlinkTimer, jiffies + MSECS(LED_CM2_BLINK_ON_INTERVAL)); ++ //PlatformSetTimer(dev, &(pLed->BlinkTimer), LED_CM2_BLINK_ON_INTERVAL); ++ } ++ else ++ { ++ pLed->BlinkingLedState = LED_ON; ++ //pLed->BlinkTimer.expires = jiffies + LED_CM2_BLINK_OFF_INTERVAL; ++ //add_timer(&(pLed->BlinkTimer)); ++ mod_timer(&pLed->BlinkTimer, jiffies + MSECS(LED_CM2_BLINK_OFF_INTERVAL)); ++ //PlatformSetTimer(dev, &(pLed->BlinkTimer), LED_CM2_BLINK_OFF_INTERVAL); ++ } ++ } ++ else ++ { ++ pLed->CurrLedState = LED_NO_LINK_BLINK; ++ } ++ break; ++ ++ case LED_CTL_LINK: ++ pLed->CurrLedState = LED_ON; ++ if( pLed->bLedBlinkInProgress == 0 ) ++ { ++ SwLedOn(dev, pLed); ++ } ++ break; ++ ++ case LED_CTL_POWER_OFF: ++ pLed->CurrLedState = LED_OFF; ++ if( pLed->bLedBlinkInProgress == 0 ) ++ { ++ SwLedOff(dev, pLed); ++ } ++ break; ++ ++ default: ++ break; ++ } ++} ++ ++ ++// ++// Description: ++// Implement each led action for SW_LED_MODE3, ++// which is customized for Sercomm Printer Server case. ++// 2006.04.21, by rcnjko. ++// ++void ++SwLedControlMode3( ++ struct net_device *dev, ++ LED_CTL_MODE LedAction ++) ++{ ++ struct r8180_priv *priv = ieee80211_priv(dev); ++ PLED_8187 pLed = &(priv->Gpio0Led); ++ ++// printk("=====+++++++++++++++++++====>%s In\n", __FUNCTION__); ++ // Decide led state ++ switch(LedAction) ++ { ++ case LED_CTL_TX: ++ case LED_CTL_RX: ++ if( pLed->bLedBlinkInProgress == 0 ) ++ { ++ pLed->bLedBlinkInProgress = 1; ++ ++ pLed->CurrLedState = LED_BLINK_CM3; ++ pLed->BlinkTimes = 2; ++ ++ if( pLed->bLedOn ) ++ pLed->BlinkingLedState = LED_OFF; ++ else ++ pLed->BlinkingLedState = LED_ON; ++ ++ //pLed->BlinkTimer.expires = jiffies + LED_CM3_BLINK_INTERVAL; ++ //add_timer(&(pLed->BlinkTimer)); ++ mod_timer(&pLed->BlinkTimer, jiffies + MSECS(LED_CM3_BLINK_INTERVAL)); ++ //PlatformSetTimer(dev, &(pLed->BlinkTimer), LED_CM3_BLINK_INTERVAL); ++ } ++ break; ++ ++ case LED_CTL_SITE_SURVEY: ++ if( pLed->bLedBlinkInProgress == 0 ) ++ { ++ pLed->bLedBlinkInProgress = 1; ++ ++ pLed->CurrLedState = LED_BLINK_CM3; ++ pLed->BlinkTimes = 10; ++ ++ if( pLed->bLedOn ) ++ pLed->BlinkingLedState = LED_OFF; ++ else ++ pLed->BlinkingLedState = LED_ON; ++ ++ //pLed->BlinkTimer.expires = jiffies + LED_CM3_BLINK_INTERVAL; ++ //add_timer(&(pLed->BlinkTimer)); ++ mod_timer(&pLed->BlinkTimer, jiffies + MSECS(LED_CM3_BLINK_INTERVAL)); ++ //PlatformSetTimer(dev, &(pLed->BlinkTimer), LED_CM3_BLINK_INTERVAL); ++ } ++ break; ++ ++ case LED_CTL_LINK: ++ pLed->CurrLedState = LED_ON; ++ if( pLed->bLedBlinkInProgress == 0 ) ++ { ++ SwLedOn(dev, pLed); ++ } ++ break; ++ ++ case LED_CTL_NO_LINK: ++ pLed->CurrLedState = LED_OFF; ++ if( pLed->bLedBlinkInProgress == 0 ) ++ { ++ SwLedOff(dev, pLed); ++ } ++ break; ++ ++ case LED_CTL_POWER_ON: ++ pLed->CurrLedState = LED_POWER_ON_BLINK; ++ SwLedOn(dev, pLed); ++ mdelay(100); ++ SwLedOff(dev, pLed); ++ break; ++ ++ case LED_CTL_POWER_OFF: ++ pLed->CurrLedState = LED_OFF; ++ if( pLed->bLedBlinkInProgress == 0 ) ++ { ++ SwLedOff(dev, pLed); ++ } ++ break; ++ ++ default: ++ break; ++ } ++} ++ ++// added by lizhaoming 2008.6.2 ++// ++// Description: ++// Implement each led action for SW_LED_MODE4, ++// which is customized for QMI 8187B minicard. ++// 2008.04.21, by chiyokolin. ++// ++void ++SwLedControlMode4( ++ struct net_device *dev, ++ LED_CTL_MODE LedAction ++ ) ++{ ++ struct r8180_priv *priv = ieee80211_priv(dev); ++ PLED_8187 pLed = &(priv->Gpio0Led); ++ ++ //printk("=====+++++++++++++++++++++====>%s In\n", __FUNCTION__); ++ // Decide led state ++ switch(LedAction) ++ { ++ case LED_CTL_TX: ++ case LED_CTL_RX: ++ //if( pLed->bLedBlinkInProgress == false && !priv->bScanInProgress)//????? ++ if( pLed->bLedBlinkInProgress == 0) ++ { ++ pLed->bLedBlinkInProgress = 1; ++ ++ pLed->CurrLedState = LED_BLINK_NORMAL; ++ pLed->BlinkTimes = 2; ++ ++ if( pLed->bLedOn ) ++ pLed->BlinkingLedState = LED_OFF; ++ else ++ pLed->BlinkingLedState = LED_ON; ++ ++ //pLed->BlinkTimer.expires = jiffies + LED_BLINK_NORMAL_INTERVAL; ++ //add_timer(&(pLed->BlinkTimer)); ++ mod_timer(&pLed->BlinkTimer, jiffies + MSECS(LED_BLINK_NORMAL_INTERVAL)); ++ //PlatformSetTimer(Adapter, &(pLed->BlinkTimer), LED_BLINK_NORMAL_INTERVAL); ++ } ++ else ++ //printk("----->LED_CTL_RX/TX bLedBlinkInProgress\n"); ++ ++ break; ++ ++ case LED_CTL_SITE_SURVEY: ++ if( pLed->bLedBlinkInProgress == 0 ) ++ { ++ ++ pLed->bLedBlinkInProgress = 1; ++ //if( priv->MgntInfo.mAssoc || priv->MgntInfo.mIbss )//////////?????? ++ //{ ++ pLed->CurrLedState = LED_SCAN_BLINK; ++ pLed->BlinkTimes = 10; ++ ++ pLed->BlinkingLedState = LED_ON; ++ ++ //pLed->BlinkTimer.expires = jiffies + LED_BLINK_NORMAL_INTERVAL; ++ //add_timer(&(pLed->BlinkTimer)); ++ mod_timer(&pLed->BlinkTimer, jiffies + MSECS(LED_BLINK_NORMAL_INTERVAL)); ++ //PlatformSetTimer(Adapter, &(pLed->BlinkTimer), LED_BLINK_NORMAL_INTERVAL); ++ //} ++ //else ++ //{ ++ // pLed->CurrLedState = LED_NO_LINK_BLINK; ++ // pLed->BlinkTimes = 24; ++ // ++ // if( pLed->bLedOn ) ++ // { ++ // pLed->BlinkingLedState = LED_OFF; ++ // ++ // pLed->BlinkTimer.expires = jiffies + LED_CM4_BLINK_ON_INTERVAL; ++ // add_timer(&(pLed->BlinkTimer)); ++ // //PlatformSetTimer(Adapter, &(pLed->BlinkTimer), LED_CM4_BLINK_ON_INTERVAL); ++ // } ++ // else ++ // { ++ // pLed->BlinkingLedState = LED_ON; ++ ++ // pLed->BlinkTimer.expires = jiffies + LED_CM4_BLINK_OFF_INTERVAL; ++ // add_timer(&(pLed->BlinkTimer)); ++ // //PlatformSetTimer(Adapter, &(pLed->BlinkTimer), LED_CM4_BLINK_OFF_INTERVAL); ++ // } ++ //} ++ } ++ else ++ { ++ if(pLed->CurrLedState != LED_NO_LINK_BLINK) ++ { ++ //if( priv->MgntInfo.mAssoc || priv->MgntInfo.mIbss )//??????????? ++ //{ ++ //} ++ //else ++ //{ ++ // pLed->CurrLedState = LED_NO_LINK_BLINK; ++ //} ++ } ++ ++ //printk("----->LED_CTL_SITE_SURVEY bLedBlinkInProgress\n"); ++ } ++ break; ++ ++ case LED_CTL_NO_LINK: ++ if( pLed->bLedBlinkInProgress == 0 ) ++ { ++ pLed->bLedBlinkInProgress = 1; ++ ++ pLed->CurrLedState = LED_NO_LINK_BLINK; ++ pLed->BlinkTimes = 24; ++ ++ if( pLed->bLedOn ) ++ { ++ pLed->BlinkingLedState = LED_OFF; ++ ++ //pLed->BlinkTimer.expires = jiffies + LED_CM4_BLINK_ON_INTERVAL; ++ //add_timer(&(pLed->BlinkTimer)); ++ mod_timer(&pLed->BlinkTimer, jiffies + MSECS(LED_CM4_BLINK_ON_INTERVAL)); ++ //PlatformSetTimer(Adapter, &(pLed->BlinkTimer), LED_CM4_BLINK_ON_INTERVAL); ++ } ++ else ++ { ++ pLed->BlinkingLedState = LED_ON; ++ ++ //pLed->BlinkTimer.expires = jiffies + LED_CM4_BLINK_OFF_INTERVAL; ++ //add_timer(&(pLed->BlinkTimer)); ++ mod_timer(&pLed->BlinkTimer, jiffies + MSECS(LED_CM4_BLINK_OFF_INTERVAL)); ++ //PlatformSetTimer(Adapter, &(pLed->BlinkTimer), LED_CM4_BLINK_OFF_INTERVAL); ++ } ++ } ++ else ++ { ++ pLed->CurrLedState = LED_NO_LINK_BLINK; ++ //printk("----->LED_CTL_NO_LINK bLedBlinkInProgress\n"); ++ } ++ break; ++ ++ case LED_CTL_LINK: ++ pLed->CurrLedState = LED_ON; ++ if( pLed->bLedBlinkInProgress == 0) ++ { ++ SwLedOn(dev, pLed); ++ } ++ else ++ ;//printk("----->LED_CTL_LINK bLedBlinkInProgress\n"); ++ ++ break; ++ ++ case LED_CTL_POWER_OFF: ++ pLed->CurrLedState = LED_OFF; ++ if(pLed->bLedBlinkInProgress) ++ { ++ printk("----->LED_CTL_POWER_OFF bLedBlinkInProgress\n"); ++ ++ //PlatformCancelTimer(Adapter, &(pLed->BlinkTimer)); ++ del_timer_sync(&(pLed->BlinkTimer)); ++ pLed->bLedBlinkInProgress = 0; ++ } ++ SwLedOff(dev, pLed); ++ break; ++ ++ default: ++ break; ++ } ++} ++ ++ ++ ++//added by lizhaoming 2008.6.3 ++// ++// Description: ++// Implement each led action for SW_LED_MODE5, ++// which is customized for DELL 8187B minicard. ++// 2008.04.24, by chiyokolin. ++// ++void ++SwLedControlMode5( ++ struct net_device *dev, ++ LED_CTL_MODE LedAction ++ ) ++{ ++ struct r8180_priv *priv = ieee80211_priv(dev); ++ PLED_8187 pLed = &(priv->Gpio0Led); ++ ++ // Decide led state ++ //printk("====++++++++++++++++++++++=====>%s In\n", __FUNCTION__); ++ switch(LedAction) ++ { ++ case LED_CTL_TX: ++ case LED_CTL_RX: ++ case LED_CTL_SITE_SURVEY: ++ case LED_CTL_POWER_ON: ++ case LED_CTL_NO_LINK: ++ case LED_CTL_LINK: ++ pLed->CurrLedState = LED_ON; ++ if( pLed->bLedBlinkInProgress == 0 ) ++ { ++ pLed->bLedBlinkInProgress = 1; ++ if(! pLed->bLedOn ) ++ pLed->BlinkingLedState = LED_ON; ++ else ++ break; ++ ++ //printk("====++++++++++++++++++++++=====>%s In LED:%d\n", __FUNCTION__, pLed->bLedOn); ++ //pLed->BlinkTimer.expires = jiffies + LED_BLINK_NORMAL_INTERVAL; ++ //add_timer(&(pLed->BlinkTimer)); ++ mod_timer(&pLed->BlinkTimer, jiffies + MSECS(LED_BLINK_NORMAL_INTERVAL)); ++ // SwLedOn(dev, pLed); ++ } ++ else ++ ;//printk("----->LED_CTL_LINK bLedBlinkInProgress\n"); ++ ++ break; ++ ++ case LED_CTL_POWER_OFF: ++ pLed->CurrLedState = LED_OFF; ++ // printk("<====++++++++++++++++++++++=====%s In LED:%d\n", __FUNCTION__, pLed->bLedOn); ++ if(pLed->bLedBlinkInProgress) ++ { ++ // printk("----->LED_CTL_POWER_OFF bLedBlinkInProgress\n"); ++ ++ //PlatformCancelTimer(Adapter, &(pLed->BlinkTimer)); ++ del_timer_sync(&(pLed->BlinkTimer)); ++ pLed->bLedBlinkInProgress = 0; ++ } ++ SwLedOff(dev, pLed); ++ break; ++ ++ default: ++ break; ++ } ++} ++ ++// ++// Callback fuction of the timer, Gpio0Led.BlinkTimer. ++// ++void ++Gpio0LedBlinkTimerCallback( ++ unsigned long data ++ ) ++{ ++ struct net_device *dev = (struct net_device *)data; ++ struct r8180_priv *priv = ieee80211_priv(dev); ++ ++// printk("=========>%s In\n", __FUNCTION__); ++ PlatformSwLedBlink(dev, &(priv->Gpio0Led)); ++} ++ ++ ++ ++// ++// Callback fuction of the timer, SwLed0.BlinkTimer. ++// ++void ++SwLed0BlinkTimerCallback( ++ unsigned long data ++ ) ++{ ++ struct net_device *dev = (struct net_device *)data; ++ struct r8180_priv *priv = ieee80211_priv(dev); ++ ++// printk("=========>%s In\n", __FUNCTION__); ++ PlatformSwLedBlink(dev, &(priv->SwLed0)); ++} ++ ++ ++ ++// ++// Callback fuction of the timer, SwLed1.BlinkTimer. ++// ++void ++SwLed1BlinkTimerCallback( ++ unsigned long data ++ ) ++{ ++ struct net_device *dev = (struct net_device *)data; ++ struct r8180_priv *priv = ieee80211_priv(dev); ++ ++// printk("=========>%s In\n", __FUNCTION__); ++ PlatformSwLedBlink(dev, &(priv->SwLed1)); ++} ++ ++void ++PlatformSwLedBlink( ++ struct net_device *dev, ++ PLED_8187 pLed ++ ) ++{ ++ struct r8180_priv *priv = ieee80211_priv(dev); ++ ++// printk("=========>%s In\n", __FUNCTION__); ++ switch(pLed->LedPin) ++ { ++ case LED_PIN_GPIO0: ++ schedule_work(&(priv->Gpio0LedWorkItem)); ++ break; ++ ++ case LED_PIN_LED0: ++ schedule_work(&(priv->SwLed0WorkItem)); ++ break; ++ ++ case LED_PIN_LED1: ++ schedule_work(&(priv->SwLed1WorkItem)); ++ break; ++ ++ default: ++ break; ++ } ++} ++ ++// ++// Callback fucntion of the workitem for SW LEDs. ++// 2006.03.01, by rcnjko. ++// ++ ++#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,20) ++void Gpio0LedWorkItemCallback(struct work_struct *work) ++{ ++ struct r8180_priv *priv = container_of(work, struct r8180_priv,Gpio0LedWorkItem); ++ struct net_device *dev = priv->ieee80211->dev; ++#else ++void ++Gpio0LedWorkItemCallback( ++ void * Context ++ ) ++{ ++ struct net_device *dev = (struct net_device *)Context; ++ struct r8180_priv *priv = ieee80211_priv(dev); ++#endif ++ PLED_8187 pLed = &(priv->Gpio0Led); ++ if (priv == NULL || dev == NULL){ ++// printk("=========>%s In\n", __FUNCTION__); ++ //printk("ft=====================>%s()\n", __FUNCTION__); ++ } ++ ++#if 0 // by lizahoming 2008.6.3 ++ if(priv->LedStrategy == SW_LED_MODE2) ++ SwLedCm2Blink(dev, pLed); ++ else ++ SwLedBlink(dev, pLed); ++#endif ++ ++#if 1 // by lizahoming 2008.6.3 ++ switch(priv->LedStrategy) ++ { ++ case SW_LED_MODE2: ++ SwLedCm2Blink(dev, pLed); ++ break; ++ case SW_LED_MODE4: ++ SwLedCm4Blink(dev, pLed); ++ break; ++ default: ++ SwLedBlink(dev, pLed); ++ break; ++ } ++#endif ++ ++ //LeaveCallbackOfRtWorkItem( &(usbdevice->Gpio0LedWorkItem) ); ++} ++ ++#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,20) ++void SwLed0WorkItemCallback(struct work_struct *work) ++{ ++ //struct r8180_priv *priv = container_of(work, struct r8180_priv, SwLed0WorkItem); ++ //struct net_device *dev = priv->dev; ++#else ++void SwLed0WorkItemCallback(void * Context) ++{ ++ //struct net_device *dev = (struct net_device *)Context; ++ //struct r8180_priv *priv = ieee80211_priv(dev); ++#endif ++ //SwLedBlink(dev, &(priv->SwLed0)); ++// printk("=========>%s In\n", __FUNCTION__); ++ ++ //LeaveCallbackOfRtWorkItem( &(usbdevice->SwLed0WorkItem) ); ++} ++ ++#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,20) ++void SwLed1WorkItemCallback(struct work_struct *work) ++{ ++ //struct r8180_priv *priv = container_of(work, struct r8180_priv, SwLed1WorkItem); ++// struct net_device *dev = priv->dev; ++#else ++void ++SwLed1WorkItemCallback( ++ void * Context ++ ) ++{ ++ //struct net_device *dev = (struct net_device *)Context; ++ //struct r8180_priv *priv = ieee80211_priv(dev); ++#endif ++// printk("=========>%s In\n", __FUNCTION__); ++ //SwLedBlink(dev, &(priv->SwLed1)); ++ ++ //LeaveCallbackOfRtWorkItem( &(usbdevice->SwLed1WorkItem) ); ++} ++ ++// ++// Implementation of LED blinking behavior. ++// It toggle off LED and schedule corresponding timer if necessary. ++// ++void ++SwLedBlink( ++ struct net_device *dev, ++ PLED_8187 pLed ++ ) ++{ ++ u8 bStopBlinking = 0; ++ ++ //printk("=========>%s In state:%d\n", __FUNCTION__, pLed->CurrLedState); ++ // Change LED according to BlinkingLedState specified. ++ if( pLed->BlinkingLedState == LED_ON ) ++ { ++ SwLedOn(dev, pLed); ++// printk("Blinktimes (%d): turn on\n", pLed->BlinkTimes); ++ } ++ else ++ { ++ SwLedOff(dev, pLed); ++// printk("Blinktimes (%d): turn off\n", pLed->BlinkTimes); ++ } ++ ++ // Determine if we shall change LED state again. ++//by lizhaoming for LED BLINK SLOWLY ++ if(pLed->CurrLedState == LED_BLINK_SLOWLY) ++ { ++ bStopBlinking = 0; ++ } else { ++ pLed->BlinkTimes--; ++ if( pLed->BlinkTimes == 0 ) ++ { ++ bStopBlinking = 1; ++ } ++ else ++ { ++ if( pLed->CurrLedState != LED_BLINK_NORMAL && ++ pLed->CurrLedState != LED_BLINK_SLOWLY && ++ pLed->CurrLedState != LED_BLINK_CM3 ) ++ { ++ bStopBlinking = 1; ++ } ++ } ++ } ++ ++ if(bStopBlinking) ++ { ++ if( pLed->CurrLedState == LED_ON && pLed->bLedOn == 0) ++ { ++ SwLedOn(dev, pLed); ++ } ++ else if(pLed->CurrLedState == LED_OFF && pLed->bLedOn == 1) ++ { ++ SwLedOff(dev, pLed); ++ } ++ ++ pLed->BlinkTimes = 0; ++ pLed->bLedBlinkInProgress = 0; ++ } ++ else ++ { ++ // Assign LED state to toggle. ++ if( pLed->BlinkingLedState == LED_ON ) ++ pLed->BlinkingLedState = LED_OFF; ++ else ++ pLed->BlinkingLedState = LED_ON; ++ ++ // Schedule a timer to toggle LED state. ++ switch( pLed->CurrLedState ) ++ { ++ case LED_BLINK_NORMAL: ++ //printk("LED_BLINK_NORMAL:Blinktimes (%d): turn off\n", pLed->BlinkTimes+1); ++ //pLed->BlinkTimer.expires = jiffies + LED_BLINK_NORMAL_INTERVAL; ++ //add_timer(&(pLed->BlinkTimer)); ++ mod_timer(&pLed->BlinkTimer, jiffies + MSECS(LED_BLINK_NORMAL_INTERVAL)); ++ //PlatformSetTimer(dev, &(pLed->BlinkTimer), LED_BLINK_NORMAL_INTERVAL); ++ break; ++ ++ case LED_BLINK_SLOWLY: ++ if( pLed->bLedOn == 1 ) ++ { ++ //printk("LED_BLINK_SLOWLY:turn off\n"); ++ //pLed->BlinkTimer.expires = jiffies + LED_BLINK_SLOWLY_INTERVAL+50;//for pcie mini card spec page 33, 250ms ++ //add_timer(&(pLed->BlinkTimer)); ++ mod_timer(&pLed->BlinkTimer, jiffies + MSECS(LED_BLINK_SLOWLY_INTERVAL+50)); ++ pLed->BlinkingLedState = LED_OFF; ++ } else { ++ //printk("LED_BLINK_SLOWLY:turn on\n"); ++ //pLed->BlinkTimer.expires = jiffies + 5000;//for pcie mini card spec page 33, 5s ++ //add_timer(&(pLed->BlinkTimer)); ++ mod_timer(&pLed->BlinkTimer, jiffies + MSECS(5000)); ++ pLed->BlinkingLedState = LED_ON; ++ } ++ break; ++ ++ case LED_BLINK_CM3: ++ //printk("LED_BLINK_CM3:Blinktimes (%d): turn off\n", pLed->BlinkTimes+1); ++ //pLed->BlinkTimer.expires = jiffies + LED_CM3_BLINK_INTERVAL; ++ //add_timer(&(pLed->BlinkTimer)); ++ mod_timer(&pLed->BlinkTimer, jiffies + MSECS(LED_CM3_BLINK_INTERVAL)); ++ //PlatformSetTimer(dev, &(pLed->BlinkTimer), LED_CM3_BLINK_INTERVAL); ++ break; ++ ++ default: ++ //printk("LED_BLINK_default:Blinktimes (%d): turn off\n", pLed->BlinkTimes+1); ++ //pLed->BlinkTimer.expires = jiffies + LED_BLINK_SLOWLY_INTERVAL; ++ //add_timer(&(pLed->BlinkTimer)); ++ mod_timer(&pLed->BlinkTimer, jiffies + MSECS(LED_BLINK_SLOWLY_INTERVAL)); ++ //PlatformSetTimer(dev, &(pLed->BlinkTimer), LED_BLINK_SLOWLY_INTERVAL); ++ break; ++ } ++ } ++} ++ ++ ++ ++// ++// Implementation of LED blinking behavior for SwLedControlMode2. ++// ++void ++SwLedCm2Blink( ++ struct net_device *dev, ++ PLED_8187 pLed ++ ) ++{ ++ struct r8180_priv *priv = ieee80211_priv(dev); ++ //PMGNT_INFO priv = &(dev->MgntInfo); ++ u8 bStopBlinking = 0; ++ ++ //printk("========+++++++++++++=>%s In\n", __FUNCTION__); ++ //To avoid LED blinking when rf is off, add by lizhaoming 2008.6.2 ++ if((priv->eRFPowerState == eRfOff) && (priv->RfOffReason>RF_CHANGE_BY_IPS)) ++ { ++ SwLedOff(dev, pLed); ++ ++ //pLed->BlinkTimer.expires = jiffies + LED_CM2_BLINK_ON_INTERVAL; ++ //add_timer(&(pLed->BlinkTimer)); ++ mod_timer(&pLed->BlinkTimer, jiffies + MSECS(LED_CM2_BLINK_ON_INTERVAL)); ++ //PlatformSetTimer(Adapter, &(pLed->BlinkTimer), LED_CM2_BLINK_ON_INTERVAL); ++ //printk(" Hw/Soft Radio Off, turn off Led\n"); ++ return; ++ } ++ ++ // Change LED according to BlinkingLedState specified. ++ if( pLed->BlinkingLedState == LED_ON ) ++ { ++ SwLedOn(dev, pLed); ++ //DMESG("Blinktimes (%d): turn on\n", pLed->BlinkTimes); ++ } ++ else ++ { ++ SwLedOff(dev, pLed); ++ //DMESG("Blinktimes (%d): turn off\n", pLed->BlinkTimes); ++ } ++ ++ //Add by lizhaoming for avoid BlinkTimers <0, 2008.6.2 ++ if(pLed->BlinkTimes > 0) ++ {//by lizhaoming 2008.6.2 ++ // Determine if we shall change LED state again. ++ pLed->BlinkTimes--; ++ }//by lizhaoming 2008.6.2 ++ ++ switch(pLed->CurrLedState) ++ { ++ case LED_BLINK_NORMAL: ++ if(pLed->BlinkTimes == 0) ++ { ++ bStopBlinking = 1; ++ } ++ break; ++/* CM2 scan blink and no link blind now not be supported ++ case LED_SCAN_BLINK: ++ if( (priv->mAssoc || priv->mIbss) && // Linked. ++ (!priv->bScanInProgress) && // Not in scan stage. ++ (pLed->BlinkTimes % 2 == 0)) // Even ++ { ++ bStopBlinking = 1; ++ } ++ break; ++ ++ case LED_NO_LINK_BLINK: ++ //Revised miniCard Ad-hoc mode "Slow Blink" by Isaiah 2006-08-03 ++ //if( (priv->mAssoc || priv->mIbss) ) // Linked. ++ if( priv->mAssoc) ++ { ++ bStopBlinking = 1; ++ } ++ else if(priv->mIbss && priv->bMediaConnect ) ++ { ++ bStopBlinking = 1; ++ } ++ break; ++*/ ++ default: ++ bStopBlinking = 1; ++ break; ++ } ++ ++ if(bStopBlinking) ++ { ++/* ++ if( priv->eRFPowerState != eRfOn ) ++ { ++ SwLedOff(dev, pLed); ++ } ++ else if( priv->bMediaConnect == 1 && pLed->bLedOn == 0) ++ { ++ SwLedOn(dev, pLed); ++ } ++ else if( priv->bMediaConnect == 0 && pLed->bLedOn == 1) ++ { ++ SwLedOff(dev, pLed); ++ } ++*/ ++ pLed->BlinkTimes = 0; ++ pLed->bLedBlinkInProgress = 0; ++ } ++ else ++ { ++ // Assign LED state to toggle. ++ if( pLed->BlinkingLedState == LED_ON ) ++ pLed->BlinkingLedState = LED_OFF; ++ else ++ pLed->BlinkingLedState = LED_ON; ++ ++ // Schedule a timer to toggle LED state. ++ switch( pLed->CurrLedState ) ++ { ++ case LED_BLINK_NORMAL: ++ //pLed->BlinkTimer.expires = jiffies + LED_BLINK_NORMAL_INTERVAL; ++ //add_timer(&(pLed->BlinkTimer)); ++ mod_timer(&pLed->BlinkTimer, jiffies + MSECS(LED_BLINK_NORMAL_INTERVAL)); ++ //PlatformSetTimer(dev, &(pLed->BlinkTimer), LED_BLINK_NORMAL_INTERVAL); ++ break; ++ ++ case LED_BLINK_SLOWLY: ++ //pLed->BlinkTimer.expires = jiffies + LED_BLINK_SLOWLY_INTERVAL; ++ //add_timer(&(pLed->BlinkTimer)); ++ mod_timer(&pLed->BlinkTimer, jiffies + MSECS(LED_BLINK_SLOWLY_INTERVAL)); ++ //PlatformSetTimer(dev, &(pLed->BlinkTimer), LED_BLINK_SLOWLY_INTERVAL); ++ break; ++ ++ case LED_SCAN_BLINK: ++ case LED_NO_LINK_BLINK: ++ if( pLed->bLedOn ) { ++ //pLed->BlinkTimer.expires = jiffies + LED_CM2_BLINK_ON_INTERVAL; ++ //add_timer(&(pLed->BlinkTimer)); ++ mod_timer(&pLed->BlinkTimer, jiffies + MSECS(LED_CM2_BLINK_ON_INTERVAL)); ++ //PlatformSetTimer(dev, &(pLed->BlinkTimer), LED_CM2_BLINK_ON_INTERVAL); ++ } else { ++ //pLed->BlinkTimer.expires = jiffies + LED_CM2_BLINK_OFF_INTERVAL; ++ //add_timer(&(pLed->BlinkTimer)); ++ mod_timer(&pLed->BlinkTimer, jiffies + MSECS(LED_CM2_BLINK_OFF_INTERVAL)); ++ //PlatformSetTimer(dev, &(pLed->BlinkTimer), LED_CM2_BLINK_OFF_INTERVAL); ++ } ++ break; ++ ++ default: ++ //RT_ASSERT(0, ("SwLedCm2Blink(): unexpected state!\n")); ++ //pLed->BlinkTimer.expires = jiffies + LED_BLINK_SLOWLY_INTERVAL; ++ //add_timer(&(pLed->BlinkTimer)); ++ mod_timer(&pLed->BlinkTimer, jiffies + MSECS(LED_BLINK_SLOWLY_INTERVAL)); ++ //PlatformSetTimer(dev, &(pLed->BlinkTimer), LED_BLINK_SLOWLY_INTERVAL); ++ break; ++ } ++ } ++} ++ ++// added by lizhaoming 2008.6.2 ++// ++// Description: ++// Implement LED blinking behavior for SW_LED_MODE4. ++// ++void ++SwLedCm4Blink( ++ struct net_device *dev, ++ PLED_8187 pLed ++ ) ++{ ++ struct r8180_priv *priv = ieee80211_priv(dev); ++ u8 bStopBlinking = 0; ++ ++ printk("======++++++++++++++++++======>%s In\n", __FUNCTION__); ++ //To avoid LED blinking when rf is off, add by Maddest 20080307 ++ if((priv->eRFPowerState == eRfOff) && (priv->RfOffReason>RF_CHANGE_BY_IPS)) ++ { ++ SwLedOff(dev, pLed); ++ ++ //pLed->BlinkTimer.expires = jiffies + LED_CM4_BLINK_ON_INTERVAL; ++ //add_timer(&(pLed->BlinkTimer)); ++ mod_timer(&pLed->BlinkTimer, jiffies + MSECS(LED_CM4_BLINK_ON_INTERVAL)); ++ //PlatformSetTimer(Adapter, &(pLed->BlinkTimer), LED_CM4_BLINK_ON_INTERVAL); ++ printk(" Hw/Soft Radio Off, turn off Led\n"); ++ return; ++ } ++ // Change LED according to BlinkingLedState specified. ++ if( pLed->BlinkingLedState == LED_ON ) ++ { ++ if(!pLed->bLedOn) ++ { ++ SwLedOn(dev, pLed); ++ } ++ printk("Blinktimes (%d): turn on\n", pLed->BlinkTimes); ++ } ++ else ++ { ++ SwLedOff(dev, pLed); ++ printk("Blinktimes (%d): turn off\n", pLed->BlinkTimes); ++ } ++ ++ //Add by Maddest for avoid BlinkTimers <0, 20080307; ++ if(pLed->BlinkTimes > 0) ++ { ++ // Determine if we shall change LED state again. ++ pLed->BlinkTimes--; ++ } ++ printk("pLed->CurrLedState %d pLed->BlinkTimes %d\n", pLed->CurrLedState,pLed->BlinkTimes); ++ switch(pLed->CurrLedState) ++ { ++ case LED_BLINK_NORMAL: ++ if(pLed->BlinkTimes == 0) ++ { ++ bStopBlinking = 1; ++ } ++ break; ++ ++/* CM2 scan blink and no link blind now not be supported ++ case LED_SCAN_BLINK: ++ if( (priv->mAssoc || priv->mIbss) && // Linked.//???????????? ++ (!priv->bScanInProgress) && // Not in scan stage.//???????????? ++ (pLed->BlinkTimes % 2 == 0)) // Even ++ { ++ bStopBlinking = 1; ++ } ++ break; ++ ++ case LED_NO_LINK_BLINK: ++ //Revised miniCard Ad-hoc mode "Slow Blink" by Isaiah 2006-08-03 ++ //if( (pMgntInfo->mAssoc || pMgntInfo->mIbss) ) // Linked. ++ if( priv->mAssoc) //???????????? ++ { ++ bStopBlinking = 1; ++ } ++ else if(priv->mIbss && priv->bMediaConnect )//???????????? ++ { ++ bStopBlinking = 1; ++ } ++ break; ++*/ ++ ++ default: ++ bStopBlinking = 1; ++ break; ++ } ++ ++ if(bStopBlinking) ++ { ++ /* ++ if( priv->eRFPowerState != eRfOn ) ++ { ++ SwLedOff(dev, pLed); ++ } ++ else if( priv->bMediaConnect == true && pLed->bLedOn == false)//???????????? ++ { ++ SwLedOn(dev, pLed); ++ } ++ else if( priv->bMediaConnect == false && pLed->bLedOn == true)//???????????? ++ { ++ SwLedOff(dev, pLed); ++ } ++ */ ++ ++ pLed->BlinkTimes = 0; ++ pLed->bLedBlinkInProgress = 0; ++ } ++ else ++ { ++ // Assign LED state to toggle. ++ if( pLed->BlinkingLedState == LED_ON ) ++ pLed->BlinkingLedState = LED_OFF; ++ else ++ pLed->BlinkingLedState = LED_ON; ++ ++ // Schedule a timer to toggle LED state. ++ switch( pLed->CurrLedState ) ++ { ++ case LED_BLINK_NORMAL: ++ //pLed->BlinkTimer.expires = jiffies + LED_BLINK_NORMAL_INTERVAL; ++ //add_timer(&(pLed->BlinkTimer)); ++ mod_timer(&pLed->BlinkTimer, jiffies + MSECS(LED_BLINK_NORMAL_INTERVAL)); ++ //PlatformSetTimer(Adapter, &(pLed->BlinkTimer), LED_BLINK_NORMAL_INTERVAL); ++ break; ++ ++ case LED_BLINK_SLOWLY: ++ //pLed->BlinkTimer.expires = jiffies + LED_BLINK_SLOWLY_INTERVAL; ++ //add_timer(&(pLed->BlinkTimer)); ++ mod_timer(&pLed->BlinkTimer, jiffies + MSECS(LED_BLINK_SLOWLY_INTERVAL)); ++ //PlatformSetTimer(Adapter, &(pLed->BlinkTimer), LED_BLINK_SLOWLY_INTERVAL); ++ break; ++ ++ case LED_SCAN_BLINK: ++ pLed->BlinkingLedState = LED_ON; ++ //pLed->BlinkTimer.expires = jiffies + LED_BLINK_NORMAL_INTERVAL; ++ //add_timer(&(pLed->BlinkTimer)); ++ mod_timer(&pLed->BlinkTimer, jiffies + MSECS(LED_BLINK_NORMAL_INTERVAL)); ++ //PlatformSetTimer(Adapter, &(pLed->BlinkTimer), LED_BLINK_NORMAL_INTERVAL); ++ ++ case LED_NO_LINK_BLINK: ++ if( pLed->bLedOn ){ ++ //pLed->BlinkTimer.expires = jiffies + LED_CM4_BLINK_ON_INTERVAL; ++ //add_timer(&(pLed->BlinkTimer)); ++ mod_timer(&pLed->BlinkTimer, jiffies + MSECS(LED_CM4_BLINK_ON_INTERVAL)); ++ //PlatformSetTimer(Adapter, &(pLed->BlinkTimer), LED_CM4_BLINK_ON_INTERVAL); ++ }else{ ++ //pLed->BlinkTimer.expires = jiffies + LED_CM4_BLINK_OFF_INTERVAL; ++ //add_timer(&(pLed->BlinkTimer)); ++ mod_timer(&pLed->BlinkTimer, jiffies + MSECS(LED_CM4_BLINK_OFF_INTERVAL)); ++ //PlatformSetTimer(Adapter, &(pLed->BlinkTimer), LED_CM4_BLINK_OFF_INTERVAL); ++ } ++ break; ++ ++ default: ++ printk("SwLedCm2Blink(): unexpected state!\n"); ++ //pLed->BlinkTimer.expires = jiffies + LED_BLINK_SLOWLY_INTERVAL; ++ //add_timer(&(pLed->BlinkTimer)); ++ mod_timer(&pLed->BlinkTimer, jiffies + MSECS(LED_BLINK_SLOWLY_INTERVAL)); ++ //PlatformSetTimer(Adapter, &(pLed->BlinkTimer), LED_BLINK_SLOWLY_INTERVAL); ++ break; ++ } ++ } ++} ++ ++void ++SwLedOn( ++ struct net_device *dev, ++ PLED_8187 pLed ++) ++{ ++ struct r8180_priv *priv = ieee80211_priv(dev); ++// printk("=========>%s(), pin:%d\n", __FUNCTION__, pLed->LedPin); ++ switch(pLed->LedPin) ++ { ++ case LED_PIN_GPIO0: ++ write_nic_byte(dev,0x0091,0x01); ++ write_nic_byte(dev,0x0090,0x00); // write 0 : LED on ++ break; ++ ++ case LED_PIN_LED0: ++ priv->PsrValue &= ~(0x01 << 4); ++ write_nic_byte(dev, PSR, priv->PsrValue); ++ break; ++ ++ case LED_PIN_LED1: ++ priv->PsrValue &= ~(0x01 << 5); ++ write_nic_byte(dev, PSR, priv->PsrValue); ++ break; ++ ++ default: ++ break; ++ } ++ ++ pLed->bLedOn = 1; ++} ++ ++void ++SwLedOff( ++ struct net_device *dev, ++ PLED_8187 pLed ++) ++{ ++ struct r8180_priv *priv = ieee80211_priv(dev); ++ ++ ++ //printk("=========>%s(), pin:%d\n", __FUNCTION__, pLed->LedPin); ++ switch(pLed->LedPin) ++ { ++ case LED_PIN_GPIO0: ++ write_nic_byte(dev,0x0091,0x01); ++ write_nic_byte(dev,0x0090,0x01); // write 1 : LED off ++ break; ++ ++ case LED_PIN_LED0: ++ priv->PsrValue |= (0x01 << 4); ++ write_nic_byte(dev, PSR, priv->PsrValue); ++ break; ++ ++ case LED_PIN_LED1: ++ priv->PsrValue |= (0x01 << 5); ++ write_nic_byte(dev, PSR, priv->PsrValue); ++ break; ++ ++ default: ++ break; ++ } ++ ++ pLed->bLedOn = 0; ++} ++ +diff -Nur linux-2.6.33/drivers/net/wireless/rtl8187b/r8187_led.h linux-lemote/drivers/net/wireless/rtl8187b/r8187_led.h +--- linux-2.6.33/drivers/net/wireless/rtl8187b/r8187_led.h 1970-01-01 01:00:00.000000000 +0100 ++++ linux-lemote/drivers/net/wireless/rtl8187b/r8187_led.h 2010-03-06 16:43:22.000000000 +0100 +@@ -0,0 +1,276 @@ ++/*++
++
++Copyright (c) Microsoft Corporation. All rights reserved.
++
++Module Name:
++ r8187_led.h
++
++Abstract:
++ definitions and stuctures for rtl8187 led control.
++
++Major Change History:
++ When Who What
++ ---------- ------ ----------------------------------------------
++ 2006-09-07 Xiong Created
++
++Notes:
++
++--*/
++
++#ifndef R8187_LED_H
++#define R8187_LED_H
++
++#include <linux/types.h>
++#include <linux/timer.h>
++
++
++/*--------------------------Define -------------------------------------------*/
++//
++// 0x7E-0x7F is reserved for SW customization. 2006.04.21, by rcnjko.
++//
++// BIT[0-7] is for CustomerID where value 0x00 and 0xFF is reserved for Realtek.
++#define EEPROM_SW_REVD_OFFSET 0x7E
++
++#define EEPROM_CID_MASK 0x00FF
++#define EEPROM_CID_RSVD0 0x00
++#define EEPROM_CID_RSVD1 0xFF
++#define EEPROM_CID_ALPHA0 0x01
++#define EEPROM_CID_SERCOMM_PS 0x02
++#define EEPROM_CID_HW_LED 0x03
++
++#define EEPROM_CID_QMI 0x07 //Added by lizhaoming 2008.6.3
++#define EEPROM_CID_DELL 0x08 //Added by lizhaoming 2008.6.3
++
++#define LED_BLINK_NORMAL_INTERVAL 100 //by lizhaoming 50 -> 100
++#define LED_BLINK_SLOWLY_INTERVAL 200
++
++// Customized for AzWave, 2006.04.03, by rcnjko.
++#define LED_CM2_BLINK_ON_INTERVAL 250
++#define LED_CM2_BLINK_OFF_INTERVAL 4750
++//
++
++// Customized for Sercomm Printer Server case, 2006.04.21, by rcnjko.
++#define LED_CM3_BLINK_INTERVAL 1500
++
++// by lizhaoming 2008.6.3: Customized for QMI.
++//
++#define LED_CM4_BLINK_ON_INTERVAL 500
++#define LED_CM4_BLINK_OFF_INTERVAL 4500
++
++
++/*--------------------------Define MACRO--------------------------------------*/
++
++
++/*------------------------------Define Struct---------------------------------*/
++typedef enum _LED_STATE_8187{
++ LED_UNKNOWN = 0,
++ LED_ON = 1,
++ LED_OFF = 2,
++ LED_BLINK_NORMAL = 3,
++ LED_BLINK_SLOWLY = 4,
++ LED_POWER_ON_BLINK = 5,
++ LED_SCAN_BLINK = 6, // LED is blinking during scanning period, the # of times to blink is depend on time for scanning.
++ LED_NO_LINK_BLINK = 7, // LED is blinking during no link state.
++ LED_BLINK_CM3 = 8, // Customzied for Sercomm Printer Server case
++}LED_STATE_8187;
++
++typedef enum _RT_CID_TYPE {
++ RT_CID_DEFAULT,
++ RT_CID_8187_ALPHA0,
++ RT_CID_8187_SERCOMM_PS,
++ RT_CID_8187_HW_LED,
++
++ RT_CID_87B_QMI , //Added by lizhaoming 2008.6.3
++ RT_CID_87B_DELL, //Added by lizhaoming 2008.6.3
++
++} RT_CID_TYPE;
++
++typedef enum _LED_STRATEGY_8187{
++ SW_LED_MODE0, // SW control 1 LED via GPIO0. It is default option.
++ SW_LED_MODE1, // 2 LEDs, through LED0 and LED1. For ALPHA.
++ SW_LED_MODE2, // SW control 1 LED via GPIO0, customized for AzWave 8187 minicard.
++ SW_LED_MODE3, // SW control 1 LED via GPIO0, customized for Sercomm Printer Server case.
++ SW_LED_MODE4, //added by lizhaoming for bluetooth 2008.6.3
++ SW_LED_MODE5, //added by lizhaoming for bluetooth 2008.6.3
++ HW_LED, // HW control 2 LEDs, LED0 and LED1 (there are 4 different control modes, see MAC.CONFIG1 for details.)
++}LED_STRATEGY_8187, *PLED_STRATEGY_8187;
++
++typedef enum _LED_PIN_8187{
++ LED_PIN_GPIO0,
++ LED_PIN_LED0,
++ LED_PIN_LED1
++}LED_PIN_8187;
++
++//by lizhaoming for LED 2008.6.23 into ieee80211.h
++//typedef enum _LED_CTL_MODE {
++// LED_CTL_POWER_ON,
++// LED_CTL_POWER_OFF,
++// LED_CTL_LINK,
++// LED_CTL_NO_LINK,
++// LED_CTL_TX,
++// LED_CTL_RX,
++// LED_CTL_SITE_SURVEY,
++//} LED_CTL_MODE;
++
++typedef struct _LED_8187{
++ LED_PIN_8187 LedPin; // Identify how to implement this SW led.
++
++ LED_STATE_8187 CurrLedState; // Current LED state.
++ u8 bLedOn; // TRUE if LED is ON, FALSE if LED is OFF.
++
++ u8 bLedBlinkInProgress; // TRUE if it is blinking, FALSE o.w..
++ u32 BlinkTimes; // Number of times to toggle led state for blinking.
++ LED_STATE_8187 BlinkingLedState; // Next state for blinking, either LED_ON or LED_OFF are.
++ struct timer_list BlinkTimer; // Timer object for led blinking.
++} LED_8187, *PLED_8187;
++
++
++
++/*------------------------Export global variable------------------------------*/
++
++
++/*------------------------------Funciton declaration--------------------------*/
++void
++InitSwLeds(
++ struct net_device *dev
++ );
++
++void
++DeInitSwLeds(
++ struct net_device *dev
++ );
++
++void
++InitLed8187(
++ struct net_device *dev,
++ PLED_8187 pLed,
++ LED_PIN_8187 LedPin,
++ void * BlinkCallBackFunc);
++
++void
++DeInitLed8187(
++ struct net_device *dev,
++ PLED_8187 pLed);
++
++void
++LedControl8187(
++ struct net_device *dev,
++ LED_CTL_MODE LedAction
++);
++
++void
++SwLedControlMode0(
++ struct net_device *dev,
++ LED_CTL_MODE LedAction
++);
++
++void
++SwLedControlMode1(
++ struct net_device *dev,
++ LED_CTL_MODE LedAction
++);
++
++void
++SwLedControlMode2(
++ struct net_device *dev,
++ LED_CTL_MODE LedAction
++);
++
++void
++SwLedControlMode3(
++ struct net_device *dev,
++ LED_CTL_MODE LedAction
++);
++
++
++void
++SwLedControlMode4(
++ struct net_device *dev,
++ LED_CTL_MODE LedAction
++);
++
++
++void
++SwLedControlMode5(
++ struct net_device *dev,
++ LED_CTL_MODE LedAction
++);
++
++void
++Gpio0LedBlinkTimerCallback(
++ unsigned long data
++ );
++
++void
++SwLed0BlinkTimerCallback(
++ unsigned long data
++ );
++
++void
++SwLed1BlinkTimerCallback(
++ unsigned long data
++ );
++
++void
++PlatformSwLedBlink(
++ struct net_device *dev,
++ PLED_8187 pLed
++ );
++#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,20)
++void
++Gpio0LedWorkItemCallback(
++ void * Context
++ );
++
++void
++SwLed0WorkItemCallback(
++ void * Context
++ );
++
++void
++SwLed1WorkItemCallback(
++ void * Context
++ );
++#else
++void
++Gpio0LedWorkItemCallback(struct work_struct *work);
++
++void
++SwLed0WorkItemCallback(struct work_struct *work);
++
++void
++SwLed1WorkItemCallback(struct work_struct *work);
++
++#endif
++void
++SwLedBlink(
++ struct net_device *dev,
++ PLED_8187 pLed
++ );
++
++void
++SwLedCm2Blink(
++ struct net_device *dev,
++ PLED_8187 pLed
++ );
++
++void
++SwLedCm4Blink(
++ struct net_device *dev,
++ PLED_8187 pLed
++ );
++
++void
++SwLedOn(
++ struct net_device *dev,
++ PLED_8187 pLed
++);
++
++void
++SwLedOff(
++ struct net_device *dev,
++ PLED_8187 pLed
++);
++
++
++#endif
+diff -Nur linux-2.6.33/drivers/net/wireless/rtl8187b/r8187_rfkill.c linux-lemote/drivers/net/wireless/rtl8187b/r8187_rfkill.c +--- linux-2.6.33/drivers/net/wireless/rtl8187b/r8187_rfkill.c 1970-01-01 01:00:00.000000000 +0100 ++++ linux-lemote/drivers/net/wireless/rtl8187b/r8187_rfkill.c 2010-03-06 16:43:22.000000000 +0100 +@@ -0,0 +1,157 @@ ++/* ++ * rtl8187b specific rfkill support ++ * ++ * NOTE: we only concern about two states ++ * eRfOff: RFKILL_STATE_SOFT_BLOCKED ++ * eRfOn: RFKILL_STATE_UNBLOCKED ++ * TODO: move led controlling source code to rfkill framework ++ * ++ * Copyright (C) 2009 Lemote Inc. ++ * Author: Wu Zhangjin <wuzhangjin@gmail.com> ++ */ ++ ++#include <linux/module.h> ++#include <linux/rfkill.h> ++#include <linux/device.h> ++ ++/* LED macros are defined in r8187.h and rfkill.h, we not use any of them here ++ * just avoid compiling erros here. ++ */ ++#undef LED ++ ++#include "r8187.h" ++#include "ieee80211/ieee80211.h" ++#include "linux/netdevice.h" ++ ++static struct rfkill *r8187b_rfkill; ++static struct work_struct r8187b_rfkill_task; ++static int initialized; ++/* turn off by default */ ++int r8187b_rfkill_state = RFKILL_USER_STATE_SOFT_BLOCKED; ++struct net_device *r8187b_dev = NULL; ++RT_RF_POWER_STATE eRfPowerStateToSet; ++ ++/* These two mutexes are used to ensure the relative rfkill status are accessed ++ * by different tasks exclusively */ ++DEFINE_MUTEX(statetoset_lock); ++DEFINE_MUTEX(state_lock); ++ ++static void r8187b_wifi_rfkill_task(struct work_struct *work) ++{ ++ if (r8187b_dev) { ++ mutex_lock(&statetoset_lock); ++ r8187b_wifi_change_rfkill_state(r8187b_dev, eRfPowerStateToSet); ++ mutex_unlock(&statetoset_lock); ++ } ++} ++ ++static int r8187b_wifi_update_rfkill_state(int status) ++{ ++ /* ensure r8187b_rfkill is initialized if dev is not initialized, means ++ * wifi driver is not start, the status is eRfOff be default. ++ */ ++ if (!r8187b_dev) ++ return eRfOff; ++ ++ if (initialized == 0) { ++ /* init the rfkill work task */ ++ INIT_WORK(&r8187b_rfkill_task, r8187b_wifi_rfkill_task); ++ initialized = 1; ++ } ++ ++ mutex_lock(&statetoset_lock); ++ if (status == 1) ++ eRfPowerStateToSet = eRfOn; ++ else if (status == 0) ++ eRfPowerStateToSet = eRfOff; ++ else if (status == 2) { ++ /* if the KEY_WLAN is pressed, just switch it! */ ++ mutex_lock(&state_lock); ++ if (r8187b_rfkill_state == RFKILL_USER_STATE_UNBLOCKED) ++ eRfPowerStateToSet = eRfOff; ++ else if (r8187b_rfkill_state == RFKILL_USER_STATE_SOFT_BLOCKED) ++ eRfPowerStateToSet = eRfOn; ++ mutex_unlock(&state_lock); ++ } ++ mutex_unlock(&statetoset_lock); ++ ++ schedule_work(&r8187b_rfkill_task); ++ ++ return eRfPowerStateToSet; ++} ++ ++static int r8187b_rfkill_set(void *data, bool blocked) ++{ ++ r8187b_wifi_update_rfkill_state(!blocked); ++ ++ return 0; ++} ++ ++static void r8187b_rfkill_query(struct rfkill *rfkill, void *data) ++{ ++ static bool blocked; ++ ++ mutex_lock(&state_lock); ++ if (r8187b_rfkill_state == RFKILL_USER_STATE_UNBLOCKED) ++ blocked = 0; ++ else if (r8187b_rfkill_state == RFKILL_USER_STATE_SOFT_BLOCKED) ++ blocked = 1; ++ mutex_unlock(&state_lock); ++ ++ rfkill_set_hw_state(rfkill, blocked); ++} ++ ++int r8187b_wifi_report_state(r8180_priv *priv) ++{ ++ mutex_lock(&state_lock); ++ r8187b_rfkill_state = RFKILL_USER_STATE_UNBLOCKED; ++ if (priv->ieee80211->bHwRadioOff && priv->eRFPowerState == eRfOff) ++ r8187b_rfkill_state = RFKILL_USER_STATE_SOFT_BLOCKED; ++ mutex_unlock(&state_lock); ++ ++ r8187b_rfkill_query(r8187b_rfkill, NULL); ++ ++ return 0; ++} ++ ++static const struct rfkill_ops r8187b_rfkill_ops = { ++ .set_block = r8187b_rfkill_set, ++ .query = r8187b_rfkill_query, ++}; ++ ++int r8187b_rfkill_init(struct net_device *dev) ++{ ++ int ret; ++ ++ /* init the r8187b device */ ++ r8187b_dev = dev; ++ ++ /* init the rfkill struct */ ++ r8187b_rfkill = rfkill_alloc("r8187b-wifi", &dev->dev, ++ RFKILL_TYPE_WLAN, &r8187b_rfkill_ops, ++ (void *)1); ++ ++ if (!r8187b_rfkill) { ++ rfkill_destroy(r8187b_rfkill); ++ printk(KERN_WARNING "r8187b: Unable to allocate rfkill\n"); ++ return -ENOMEM; ++ } ++ ret = rfkill_register(r8187b_rfkill); ++ if (ret) { ++ rfkill_destroy(r8187b_rfkill); ++ return ret; ++ } ++ ++ /* The default status is passed to the rfkill module */ ++ ++ return 0; ++} ++ ++void r8187b_rfkill_exit(void) ++{ ++ if (r8187b_rfkill) { ++ rfkill_unregister(r8187b_rfkill); ++ rfkill_destroy(r8187b_rfkill); ++ } ++ r8187b_rfkill = NULL; ++} +diff -Nur linux-2.6.33/drivers/net/wireless/rtl8187b/readme linux-lemote/drivers/net/wireless/rtl8187b/readme +--- linux-2.6.33/drivers/net/wireless/rtl8187b/readme 1970-01-01 01:00:00.000000000 +0100 ++++ linux-lemote/drivers/net/wireless/rtl8187b/readme 2010-03-06 16:43:22.000000000 +0100 +@@ -0,0 +1,124 @@ ++rtl8187 Linux kernel driver ++Released under the terms of GNU General Public Licence (GPL) ++Copyright(c) Andrea Merello - 2004,2005 ++ ++Portions of this driver are based on other projects, please see the notes ++in the source files for detail. ++A special thanks go to Realtek corp for their support and to David Young ++------------------------------------------------------------------------------ ++ ++This is an attempt to write somethig that can make rtl8187 usb dongle wifi card ++on Linux using only opensource stuff. ++The rtl8225 radio is supported. ++ ++It's in early development stage so don't expect too much from it ++(also use it at your own risk!) ++This should be considered just a fragment of code.. using it on your(any) ++system is at your own risk! Please note that I never supported the idea to ++use it in any way, so i cannot be considered responsible in any way for ++anything deriving by it usage. ++ ++Anyway for now we have monitor mode and managed mode ++basically working! This isn't necessary stable, but seems to work.. ++ ++This driver is still under development and very far from perfect. It should work on x86, ++Other archs are untested.. ++ ++To compile the driver simply run make. ++ ++The driver contains also the ieee80211.h and ieee80211_crypt.h from the ieee stack. ++Note that for some reasons this stack is NOT the same that will be included in newer ++2.6 kernel. I will try to port to this stack as soon as it will have enought features ++to support 8187 cards. ++Please note that you will have to make sure the two .h files are the same of the ieee ++stack. ++In other words when you download from the CVS this driver and the ieee80211 stack a good ++idea is to copy the ieee80211.h and ieee80211_crypt.h from the ieee directory to the drv ++directory ++ ++Warning during compile are OK ++ ++To wake up the nic run: ++ ++ ifconfig <ifacename> up ++ ++(where <ifacename> is your network device for wlan card). ++ ++Please note that the default interface name is wlanX. ++ ++Please note thet this will take several seconds.. ++ ++If you would like to set the interface name to something else you may use the ++'devname=' module parameter. For example: ++ ++ insmod r8187.ko ifname=eth%d ++ ++will set the interface name of this device to something like eth0. ++ ++Once the nic is up it can be put in a monitor mode by running: ++ ++ iwconfig <ifacename> mode monitor ++ ++and channel number may be changed by running: ++ ++ iwconfig <ifacename> channel XX ++ ++ ++In monitor mode a choice may be made via iwpriv if the nic should pass packets ++with bad crc or drop them. ++ ++To put the nic in managed mode run: ++ ++ iwconfig <ifacename> mode managed ++ ++In managed mode there is support for ++ ++ iwlist scan ++ ++that should report the currently available networks. ++Please note that in managed mode channels cannot be changed manually. ++ ++To associate with a network ++ ++ iwconfig <ifacename> essid XXXXX ++ ++where XXXXX is the network essid (name) reported by 'iwlist scan'. Please ++note that essid is case sensitive. ++ ++If your network is not broadcasting the ESSID, then you need to specify *also* ++the AP MAC address ++ ++ iwconfig <ifacename> ap XX:XX:XX:XX:XX:XX ++ ++The driver accepts another boolean parameter: hwseqnum ++If set to 1 it lets the card HW take care of the sequence number of the TXed ++frames. Altought in managed mode I can't see an important reason to use HW to ++do that, when we'll start to TX beacons in master (AP) and ad-hoc modes most ++probably it will be extremely useful (since most probably we will use two HW ++queues). ++ ++I'm unsure if it will work correctly on all NICs.. reports are *VERY, VERY* apreciated.. ++ ++ ++ WEP ++ === ++ ++WEP encryption should work. For now it's done by host, not by the nic. Key can be set with: ++Key can be set with ++ ++ iwconfig <ifacename> key 12345... ++ ++WEP is supported via software thanks to the ipw stack. ++ ++Shared and open authentication are supported ++ ++ IWPRIV ++ ====== ++ ++This driver supports some private handlers: ++-badcrc: let you choose to kill or to pass to the upper layer frames with bad crc in monitor mode ++-activescan: if 0 the driver will avoid to send probe requests, sanning will be only on beacon basis ++ ++ ++If you have some question/comments please feel free to write me. ++ +diff -Nur linux-2.6.33/drivers/platform/Kconfig linux-lemote/drivers/platform/Kconfig +--- linux-2.6.33/drivers/platform/Kconfig 2010-02-24 19:52:17.000000000 +0100 ++++ linux-lemote/drivers/platform/Kconfig 2010-03-06 16:43:22.000000000 +0100 +@@ -1,3 +1,7 @@ + if X86 + source "drivers/platform/x86/Kconfig" + endif ++ ++if MIPS ++source "drivers/platform/mips/Kconfig" ++endif +diff -Nur linux-2.6.33/drivers/platform/Makefile linux-lemote/drivers/platform/Makefile +--- linux-2.6.33/drivers/platform/Makefile 2010-02-24 19:52:17.000000000 +0100 ++++ linux-lemote/drivers/platform/Makefile 2010-03-06 16:43:22.000000000 +0100 +@@ -3,3 +3,4 @@ + # + + obj-$(CONFIG_X86) += x86/ ++obj-$(CONFIG_MIPS) += mips/ +diff -Nur linux-2.6.33/drivers/platform/mips/Kconfig linux-lemote/drivers/platform/mips/Kconfig +--- linux-2.6.33/drivers/platform/mips/Kconfig 1970-01-01 01:00:00.000000000 +0100 ++++ linux-lemote/drivers/platform/mips/Kconfig 2010-03-06 16:43:22.000000000 +0100 +@@ -0,0 +1,43 @@ ++# ++# MIPS Platform Specific Drivers ++# ++ ++menuconfig MIPS_PLATFORM_DEVICES ++ bool "MIPS Platform Specific Device Drivers" ++ default y ++ help ++ Say Y here to get to see options for device drivers of various ++ MIPS platforms, including vendor-specific netbook/laptop/pc extension ++ drivers. This option alone does not add any kernel code. ++ ++ If you say N, all options in this submenu will be skipped and disabled. ++ ++if MIPS_PLATFORM_DEVICES ++ ++config LEMOTE_YEELOONG2F ++ tristate "Lemote YeeLoong Laptop" ++ depends on LEMOTE_MACH2F ++ select BACKLIGHT_CLASS_DEVICE ++ select POWER_SUPPLY ++ select HWMON ++ select VIDEO_OUTPUT_CONTROL ++ select INPUT_SPARSEKMAP ++ depends on INPUT ++ help ++ YeeLoong netbook is a mini laptop made by Lemote, which is basically ++ compatible to FuLoong2F mini PC, but it has an extra Embedded ++ Controller(kb3310b) for battery, hotkey, backlight, temperature and ++ fan management. ++ ++config LEMOTE_LYNLOONG2F ++ tristate "Lemote LynLoong PC" ++ depends on LEMOTE_MACH2F ++ select BACKLIGHT_CLASS_DEVICE ++ select VIDEO_OUTPUT_CONTROL ++ help ++ LynLoong PC is an AllINONE machine made by Lemote, which is basically ++ compatible to FuLoong2F Mini PC, the only difference is that it has a ++ size-fixed screen: 1360x768 with sisfb video driver. and also, it has ++ its own specific suspend support. ++ ++endif # MIPS_PLATFORM_DEVICES +diff -Nur linux-2.6.33/drivers/platform/mips/lynloong_pc.c linux-lemote/drivers/platform/mips/lynloong_pc.c +--- linux-2.6.33/drivers/platform/mips/lynloong_pc.c 1970-01-01 01:00:00.000000000 +0100 ++++ linux-lemote/drivers/platform/mips/lynloong_pc.c 2010-03-06 16:43:22.000000000 +0100 +@@ -0,0 +1,511 @@ ++/* ++ * Driver for LynLoong PC extras ++ * ++ * Copyright (C) 2009 Lemote Inc. ++ * Author: Wu Zhangjin <wuzhangjin@gmail.com>, Xiang Yu <xiangy@lemote.com> ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License version 2 as ++ * published by the Free Software Foundation. ++ */ ++ ++#include <linux/err.h> ++#include <linux/platform_device.h> ++#include <linux/backlight.h> /* for backlight subdriver */ ++#include <linux/fb.h> ++#include <linux/video_output.h> /* for video output subdriver */ ++#include <linux/delay.h> /* for suspend support */ ++ ++#include <cs5536/cs5536.h> ++#include <cs5536/cs5536_mfgpt.h> ++ ++#include <loongson.h> ++ ++static u32 gpio_base, mfgpt_base; ++ ++static void set_gpio_reg_high(int gpio, int reg) ++{ ++ u32 val; ++ ++ val = inl(gpio_base + reg); ++ val |= (1 << gpio); ++ val &= ~(1 << (16 + gpio)); ++ outl(val, gpio_base + reg); ++ mmiowb(); ++} ++ ++static void set_gpio_reg_low(int gpio, int reg) ++{ ++ u32 val; ++ ++ val = inl(gpio_base + reg); ++ val |= (1 << (16 + gpio)); ++ val &= ~(1 << gpio); ++ outl(val, gpio_base + reg); ++ mmiowb(); ++} ++ ++static void set_gpio_output_low(int gpio) ++{ ++ set_gpio_reg_high(gpio, GPIOL_OUT_EN); ++ set_gpio_reg_low(gpio, GPIOL_OUT_VAL); ++} ++ ++static void set_gpio_output_high(int gpio) ++{ ++ set_gpio_reg_high(gpio, GPIOL_OUT_EN); ++ set_gpio_reg_high(gpio, GPIOL_OUT_VAL); ++} ++ ++/* backlight subdriver */ ++ ++#define MAX_BRIGHTNESS 100 ++#define DEFAULT_BRIGHTNESS 50 ++#define MIN_BRIGHTNESS 0 ++static unsigned int level; ++ ++DEFINE_SPINLOCK(backlight_lock); ++/* Tune the brightness */ ++static void setup_mfgpt2(void) ++{ ++ unsigned long flags; ++ ++ spin_lock_irqsave(&backlight_lock, flags); ++ ++ /* Set MFGPT2 comparator 1,2 */ ++ outw(MAX_BRIGHTNESS-level, MFGPT2_CMP1); ++ outw(MAX_BRIGHTNESS, MFGPT2_CMP2); ++ /* Clear MFGPT2 UP COUNTER */ ++ outw(0, MFGPT2_CNT); ++ /* Enable counter, compare mode, 32k */ ++ outw(0x8280, MFGPT2_SETUP); ++ ++ spin_unlock_irqrestore(&backlight_lock, flags); ++} ++ ++static int lynloong_set_brightness(struct backlight_device *bd) ++{ ++ level = (bd->props.fb_blank == FB_BLANK_UNBLANK && ++ bd->props.power == FB_BLANK_UNBLANK) ? ++ bd->props.brightness : 0; ++ ++ if (level > MAX_BRIGHTNESS) ++ level = MAX_BRIGHTNESS; ++ else if (level < MIN_BRIGHTNESS) ++ level = MIN_BRIGHTNESS; ++ ++ setup_mfgpt2(); ++ ++ return 0; ++} ++ ++static int lynloong_get_brightness(struct backlight_device *bd) ++{ ++ return level; ++} ++ ++static struct backlight_ops backlight_ops = { ++ .get_brightness = lynloong_get_brightness, ++ .update_status = lynloong_set_brightness, ++}; ++ ++static struct backlight_device *lynloong_backlight_dev; ++ ++static int lynloong_backlight_init(void) ++{ ++ int ret; ++ u32 hi; ++ ++ /* Get gpio_base */ ++ _rdmsr(DIVIL_MSR_REG(DIVIL_LBAR_GPIO), &hi, &gpio_base); ++ /* Get mfgpt_base */ ++ _rdmsr(DIVIL_MSR_REG(DIVIL_LBAR_MFGPT), &hi, &mfgpt_base); ++ /* Get gpio_base */ ++ _rdmsr(DIVIL_MSR_REG(DIVIL_LBAR_GPIO), &hi, &gpio_base); ++ ++ /* Select for mfgpt */ ++ set_gpio_reg_high(7, GPIOL_OUT_AUX1_SEL); ++ /* Enable brightness controlling */ ++ set_gpio_output_high(7); ++ ++ lynloong_backlight_dev = backlight_device_register("backlight0", NULL, ++ NULL, &backlight_ops); ++ ++ if (IS_ERR(lynloong_backlight_dev)) { ++ ret = PTR_ERR(lynloong_backlight_dev); ++ return ret; ++ } ++ ++ lynloong_backlight_dev->props.max_brightness = MAX_BRIGHTNESS; ++ lynloong_backlight_dev->props.brightness = DEFAULT_BRIGHTNESS; ++ backlight_update_status(lynloong_backlight_dev); ++ ++ return 0; ++} ++ ++static void lynloong_backlight_exit(void) ++{ ++ if (lynloong_backlight_dev) { ++ backlight_device_unregister(lynloong_backlight_dev); ++ lynloong_backlight_dev = NULL; ++ } ++ /* Disable brightness controlling */ ++ set_gpio_output_low(7); ++} ++ ++/* video output driver */ ++static int vo_status = 1; ++ ++static int lcd_video_output_get(struct output_device *od) ++{ ++ return vo_status; ++} ++ ++static int lcd_video_output_set(struct output_device *od) ++{ ++ int i; ++ unsigned long status; ++ ++ status = !!od->request_state; ++ ++ if (status == 0) { ++ /* Set the current status as off */ ++ vo_status = 0; ++ /* Turn off the backlight */ ++ set_gpio_output_low(11); ++ for (i = 0; i < 0x500; i++) ++ delay(); ++ /* Turn off the LCD */ ++ set_gpio_output_high(8); ++ } else { ++ /* Turn on the LCD */ ++ set_gpio_output_low(8); ++ for (i = 0; i < 0x500; i++) ++ delay(); ++ /* Turn on the backlight */ ++ set_gpio_output_high(11); ++ /* Set the current status as on */ ++ vo_status = 1; ++ } ++ ++ return 0; ++} ++ ++static struct output_properties lcd_output_properties = { ++ .set_state = lcd_video_output_set, ++ .get_status = lcd_video_output_get, ++}; ++ ++static struct output_device *lcd_output_dev; ++ ++static void lynloong_lcd_vo_set(int status) ++{ ++ lcd_output_dev->request_state = status; ++ lcd_video_output_set(lcd_output_dev); ++} ++ ++static int lynloong_vo_init(void) ++{ ++ int ret; ++ ++ /* Register video output device: lcd */ ++ lcd_output_dev = video_output_register("LCD", NULL, NULL, ++ &lcd_output_properties); ++ ++ if (IS_ERR(lcd_output_dev)) { ++ ret = PTR_ERR(lcd_output_dev); ++ lcd_output_dev = NULL; ++ return ret; ++ } ++ /* Ensure LCD is on by default */ ++ lynloong_lcd_vo_set(1); ++ ++ return 0; ++} ++ ++static void lynloong_vo_exit(void) ++{ ++ if (lcd_output_dev) { ++ video_output_unregister(lcd_output_dev); ++ lcd_output_dev = NULL; ++ } ++} ++ ++/* suspend support */ ++ ++#ifdef CONFIG_PM ++ ++static u32 smb_base; ++ ++/* I2C operations */ ++ ++static int i2c_wait(void) ++{ ++ char c; ++ int i; ++ ++ udelay(1000); ++ for (i = 0; i < 20; i++) { ++ c = inb(smb_base | SMB_STS); ++ if (c & (SMB_STS_BER | SMB_STS_NEGACK)) ++ return -1; ++ if (c & SMB_STS_SDAST) ++ return 0; ++ udelay(100); ++ } ++ return -2; ++} ++ ++static void i2c_read_single(int addr, int regNo, char *value) ++{ ++ unsigned char c; ++ ++ /* Start condition */ ++ c = inb(smb_base | SMB_CTRL1); ++ outb(c | SMB_CTRL1_START, smb_base | SMB_CTRL1); ++ i2c_wait(); ++ ++ /* Send slave address */ ++ outb(addr & 0xfe, smb_base | SMB_SDA); ++ i2c_wait(); ++ ++ /* Acknowledge smbus */ ++ c = inb(smb_base | SMB_CTRL1); ++ outb(c | SMB_CTRL1_ACK, smb_base | SMB_CTRL1); ++ ++ /* Send register index */ ++ outb(regNo, smb_base | SMB_SDA); ++ i2c_wait(); ++ ++ /* Acknowledge smbus */ ++ c = inb(smb_base | SMB_CTRL1); ++ outb(c | SMB_CTRL1_ACK, smb_base | SMB_CTRL1); ++ ++ /* Start condition again */ ++ c = inb(smb_base | SMB_CTRL1); ++ outb(c | SMB_CTRL1_START, smb_base | SMB_CTRL1); ++ i2c_wait(); ++ ++ /* Send salve address again */ ++ outb(1 | addr, smb_base | SMB_SDA); ++ i2c_wait(); ++ ++ /* Acknowledge smbus */ ++ c = inb(smb_base | SMB_CTRL1); ++ outb(c | SMB_CTRL1_ACK, smb_base | SMB_CTRL1); ++ ++ /* Read data */ ++ *value = inb(smb_base | SMB_SDA); ++ ++ /* Stop condition */ ++ outb(SMB_CTRL1_STOP, smb_base | SMB_CTRL1); ++ i2c_wait(); ++} ++ ++static void i2c_write_single(int addr, int regNo, char value) ++{ ++ unsigned char c; ++ ++ /* Start condition */ ++ c = inb(smb_base | SMB_CTRL1); ++ outb(c | SMB_CTRL1_START, smb_base | SMB_CTRL1); ++ i2c_wait(); ++ /* Send slave address */ ++ outb(addr & 0xfe, smb_base | SMB_SDA); ++ i2c_wait();; ++ ++ /* Send register index */ ++ outb(regNo, smb_base | SMB_SDA); ++ i2c_wait(); ++ ++ /* Write data */ ++ outb(value, smb_base | SMB_SDA); ++ i2c_wait(); ++ /* Stop condition */ ++ outb(SMB_CTRL1_STOP, smb_base | SMB_CTRL1); ++ i2c_wait(); ++} ++ ++static void stop_clock(int clk_reg, int clk_sel) ++{ ++ u8 value; ++ ++ i2c_read_single(0xd3, clk_reg, &value); ++ value &= ~(1 << clk_sel); ++ i2c_write_single(0xd2, clk_reg, value); ++} ++ ++static void enable_clock(int clk_reg, int clk_sel) ++{ ++ u8 value; ++ ++ i2c_read_single(0xd3, clk_reg, &value); ++ value |= (1 << clk_sel); ++ i2c_write_single(0xd2, clk_reg, value); ++} ++ ++static char cached_clk_freq; ++static char cached_pci_fixed_freq; ++ ++static void decrease_clk_freq(void) ++{ ++ char value; ++ ++ i2c_read_single(0xd3, 1, &value); ++ cached_clk_freq = value; ++ ++ /* Select frequency by software */ ++ value |= (1 << 1); ++ /* CPU, 3V66, PCI : 100, 66, 33(1) */ ++ value |= (1 << 2); ++ i2c_write_single(0xd2, 1, value); ++ ++ /* Cache the pci frequency */ ++ i2c_read_single(0xd3, 14, &value); ++ cached_pci_fixed_freq = value; ++ ++ /* Enable PCI fix mode */ ++ value |= (1 << 5); ++ /* 3V66, PCI : 64MHz, 32MHz */ ++ value |= (1 << 3); ++ i2c_write_single(0xd2, 14, value); ++ ++} ++ ++static void resume_clk_freq(void) ++{ ++ i2c_write_single(0xd2, 1, cached_clk_freq); ++ i2c_write_single(0xd2, 14, cached_pci_fixed_freq); ++} ++ ++static void stop_clocks(void) ++{ ++ /* CPU Clock Register */ ++ stop_clock(2, 5); /* not used */ ++ stop_clock(2, 6); /* not used */ ++ stop_clock(2, 7); /* not used */ ++ ++ /* PCI Clock Register */ ++ stop_clock(3, 1); /* 8100 */ ++ stop_clock(3, 5); /* SIS */ ++ stop_clock(3, 0); /* not used */ ++ stop_clock(3, 6); /* not used */ ++ ++ /* PCI 48M Clock Register */ ++ stop_clock(4, 6); /* USB grounding */ ++ stop_clock(4, 5); /* REF(5536_14M) */ ++ ++ /* 3V66 Control Register */ ++ stop_clock(5, 0); /* VCH_CLK..., grounding */ ++} ++ ++static void enable_clocks(void) ++{ ++ enable_clock(3, 1); /* 8100 */ ++ enable_clock(3, 5); /* SIS */ ++ ++ enable_clock(4, 6); ++ enable_clock(4, 5); /* REF(5536_14M) */ ++ ++ enable_clock(5, 0); /* VCH_CLOCK, grounding */ ++} ++ ++static int lynloong_suspend(struct device *dev) ++{ ++ /* Disable AMP */ ++ set_gpio_output_high(6); ++ /* Turn off LCD */ ++ lynloong_lcd_vo_set(0); ++ ++ /* Stop the clocks of some devices */ ++ stop_clocks(); ++ ++ /* Decrease the external clock frequency */ ++ decrease_clk_freq(); ++ ++ return 0; ++} ++ ++static int lynloong_resume(struct device *dev) ++{ ++ /* Turn on the LCD */ ++ lynloong_lcd_vo_set(1); ++ ++ /* Resume clock frequency, enable the relative clocks */ ++ resume_clk_freq(); ++ enable_clocks(); ++ ++ /* Enable AMP */ ++ set_gpio_output_low(6); ++ ++ return 0; ++} ++ ++static const SIMPLE_DEV_PM_OPS(lynloong_pm_ops, lynloong_suspend, ++ lynloong_resume); ++#endif /* !CONFIG_PM */ ++ ++static struct platform_device_id platform_device_ids[] = { ++ { ++ .name = "lynloong_pc", ++ }, ++ {} ++}; ++ ++MODULE_DEVICE_TABLE(platform, platform_device_ids); ++ ++static struct platform_driver platform_driver = { ++ .driver = { ++ .name = "lynloong_pc", ++ .owner = THIS_MODULE, ++#ifdef CONFIG_PM ++ .pm = &lynloong_pm_ops, ++#endif ++ }, ++ .id_table = platform_device_ids, ++}; ++ ++static int __init lynloong_init(void) ++{ ++ int ret; ++ ++ pr_info("Load LynLoong Platform Specific Driver.\n"); ++ ++ /* Register platform stuff */ ++ ret = platform_driver_register(&platform_driver); ++ if (ret) { ++ pr_err("Fail to register lynloong platform driver.\n"); ++ return ret; ++ } ++ ++ ret = lynloong_backlight_init(); ++ if (ret) { ++ pr_err("Fail to register lynloong backlight driver.\n"); ++ return ret; ++ } ++ ++ ret = lynloong_vo_init(); ++ if (ret) { ++ pr_err("Fail to register lynloong backlight driver.\n"); ++ lynloong_vo_exit(); ++ return ret; ++ } ++ ++ return 0; ++} ++ ++static void __exit lynloong_exit(void) ++{ ++ lynloong_vo_exit(); ++ lynloong_backlight_exit(); ++ platform_driver_unregister(&platform_driver); ++ ++ pr_info("Unload LynLoong Platform Specific Driver.\n"); ++} ++ ++module_init(lynloong_init); ++module_exit(lynloong_exit); ++ ++MODULE_AUTHOR("Wu Zhangjin <wuzhangjin@gmail.com>; Xiang Yu <xiangy@lemote.com>"); ++MODULE_DESCRIPTION("LynLoong PC driver"); ++MODULE_LICENSE("GPL"); +diff -Nur linux-2.6.33/drivers/platform/mips/Makefile linux-lemote/drivers/platform/mips/Makefile +--- linux-2.6.33/drivers/platform/mips/Makefile 1970-01-01 01:00:00.000000000 +0100 ++++ linux-lemote/drivers/platform/mips/Makefile 2010-03-06 16:43:22.000000000 +0100 +@@ -0,0 +1,7 @@ ++# ++# Makefile for MIPS Platform-Specific Drivers ++# ++ ++obj-$(CONFIG_LEMOTE_YEELOONG2F) += yeeloong_laptop.o ++ ++obj-$(CONFIG_LEMOTE_LYNLOONG2F) += lynloong_pc.o +diff -Nur linux-2.6.33/drivers/platform/mips/yeeloong_ecrom.c linux-lemote/drivers/platform/mips/yeeloong_ecrom.c +--- linux-2.6.33/drivers/platform/mips/yeeloong_ecrom.c 1970-01-01 01:00:00.000000000 +0100 ++++ linux-lemote/drivers/platform/mips/yeeloong_ecrom.c 2010-03-06 16:43:22.000000000 +0100 +@@ -0,0 +1,943 @@ ++/* ++ * Driver for flushing/dumping ROM of EC on YeeLoong laptop ++ * ++ * Copyright (C) 2009 Lemote Inc. ++ * Author: liujl <liujl@lemote.com> ++ * ++ * NOTE : ++ * The EC resources accessing and programming are supported. ++ */ ++ ++#include <linux/proc_fs.h> ++#include <linux/miscdevice.h> ++#include <linux/init.h> ++#include <linux/delay.h> ++ ++#include <ec_kb3310b.h> ++ ++#define EC_MISC_DEV "ec_misc" ++#define EC_IOC_MAGIC 'E' ++ ++/* ec registers range */ ++#define EC_MAX_REGADDR 0xFFFF ++#define EC_MIN_REGADDR 0xF000 ++#define EC_RAM_ADDR 0xF800 ++ ++/* version burned address */ ++#define VER_ADDR 0xf7a1 ++#define VER_MAX_SIZE 7 ++#define EC_ROM_MAX_SIZE 0x10000 ++ ++/* ec internal register */ ++#define REG_POWER_MODE 0xF710 ++#define FLAG_NORMAL_MODE 0x00 ++#define FLAG_IDLE_MODE 0x01 ++#define FLAG_RESET_MODE 0x02 ++ ++/* ec update program flag */ ++#define PROGRAM_FLAG_NONE 0x00 ++#define PROGRAM_FLAG_IE 0x01 ++#define PROGRAM_FLAG_ROM 0x02 ++ ++/* XBI relative registers */ ++#define REG_XBISEG0 0xFEA0 ++#define REG_XBISEG1 0xFEA1 ++#define REG_XBIRSV2 0xFEA2 ++#define REG_XBIRSV3 0xFEA3 ++#define REG_XBIRSV4 0xFEA4 ++#define REG_XBICFG 0xFEA5 ++#define REG_XBICS 0xFEA6 ++#define REG_XBIWE 0xFEA7 ++#define REG_XBISPIA0 0xFEA8 ++#define REG_XBISPIA1 0xFEA9 ++#define REG_XBISPIA2 0xFEAA ++#define REG_XBISPIDAT 0xFEAB ++#define REG_XBISPICMD 0xFEAC ++#define REG_XBISPICFG 0xFEAD ++#define REG_XBISPIDATR 0xFEAE ++#define REG_XBISPICFG2 0xFEAF ++ ++/* commands definition for REG_XBISPICMD */ ++#define SPICMD_WRITE_STATUS 0x01 ++#define SPICMD_BYTE_PROGRAM 0x02 ++#define SPICMD_READ_BYTE 0x03 ++#define SPICMD_WRITE_DISABLE 0x04 ++#define SPICMD_READ_STATUS 0x05 ++#define SPICMD_WRITE_ENABLE 0x06 ++#define SPICMD_HIGH_SPEED_READ 0x0B ++#define SPICMD_POWER_DOWN 0xB9 ++#define SPICMD_SST_EWSR 0x50 ++#define SPICMD_SST_SEC_ERASE 0x20 ++#define SPICMD_SST_BLK_ERASE 0x52 ++#define SPICMD_SST_CHIP_ERASE 0x60 ++#define SPICMD_FRDO 0x3B ++#define SPICMD_SEC_ERASE 0xD7 ++#define SPICMD_BLK_ERASE 0xD8 ++#define SPICMD_CHIP_ERASE 0xC7 ++ ++/* bits definition for REG_XBISPICFG */ ++#define SPICFG_AUTO_CHECK 0x01 ++#define SPICFG_SPI_BUSY 0x02 ++#define SPICFG_DUMMY_READ 0x04 ++#define SPICFG_EN_SPICMD 0x08 ++#define SPICFG_LOW_SPICS 0x10 ++#define SPICFG_EN_SHORT_READ 0x20 ++#define SPICFG_EN_OFFSET_READ 0x40 ++#define SPICFG_EN_FAST_READ 0x80 ++ ++/* watchdog timer registers */ ++#define REG_WDTCFG 0xfe80 ++#define REG_WDTPF 0xfe81 ++#define REG_WDT 0xfe82 ++ ++/* lpc configure register */ ++#define REG_LPCCFG 0xfe95 ++ ++/* 8051 reg */ ++#define REG_PXCFG 0xff14 ++ ++/* Fan register in KB3310 */ ++#define REG_ECFAN_SPEED_LEVEL 0xf4e4 ++#define REG_ECFAN_SWITCH 0xf4d2 ++ ++/* the ec flash rom id number */ ++#define EC_ROM_PRODUCT_ID_SPANSION 0x01 ++#define EC_ROM_PRODUCT_ID_MXIC 0xC2 ++#define EC_ROM_PRODUCT_ID_AMIC 0x37 ++#define EC_ROM_PRODUCT_ID_EONIC 0x1C ++ ++/* misc ioctl operations */ ++#define IOCTL_RDREG _IOR(EC_IOC_MAGIC, 1, int) ++#define IOCTL_WRREG _IOW(EC_IOC_MAGIC, 2, int) ++#define IOCTL_READ_EC _IOR(EC_IOC_MAGIC, 3, int) ++#define IOCTL_PROGRAM_IE _IOW(EC_IOC_MAGIC, 4, int) ++#define IOCTL_PROGRAM_EC _IOW(EC_IOC_MAGIC, 5, int) ++ ++/* start address for programming of EC content or IE */ ++/* ec running code start address */ ++#define EC_START_ADDR 0x00000000 ++/* ec information element storing address */ ++#define IE_START_ADDR 0x00020000 ++ ++/* EC state */ ++#define EC_STATE_IDLE 0x00 /* ec in idle state */ ++#define EC_STATE_BUSY 0x01 /* ec in busy state */ ++ ++/* timeout value for programming */ ++#define EC_FLASH_TIMEOUT 0x1000 /* ec program timeout */ ++/* command checkout timeout including cmd to port or state flag check */ ++#define EC_CMD_TIMEOUT 0x1000 ++#define EC_SPICMD_STANDARD_TIMEOUT (4 * 1000) /* unit : us */ ++#define EC_MAX_DELAY_UNIT (10) /* every time for polling */ ++#define SPI_FINISH_WAIT_TIME 10 ++/* EC content max size */ ++#define EC_CONTENT_MAX_SIZE (64 * 1024) ++#define IE_CONTENT_MAX_SIZE (0x100000 - IE_START_ADDR) ++ ++/* the register operation access struct */ ++struct ec_reg { ++ u32 addr; /* the address of kb3310 registers */ ++ u8 val; /* the register value */ ++}; ++ ++struct ec_info { ++ u32 start_addr; ++ u32 size; ++ u8 *buf; ++}; ++ ++/* open for using rom protection action */ ++#define EC_ROM_PROTECTION ++ ++/* enable the chip reset mode */ ++static int ec_init_reset_mode(void) ++{ ++ int timeout; ++ unsigned char status = 0; ++ int ret = 0; ++ ++ /* make chip goto reset mode */ ++ ret = ec_query_seq(CMD_INIT_RESET_MODE); ++ if (ret < 0) { ++ printk(KERN_ERR "ec init reset mode failed.\n"); ++ goto out; ++ } ++ ++ /* make the action take active */ ++ timeout = EC_CMD_TIMEOUT; ++ status = ec_read(REG_POWER_MODE) & FLAG_RESET_MODE; ++ while (timeout--) { ++ if (status) { ++ udelay(EC_REG_DELAY); ++ break; ++ } ++ status = ec_read(REG_POWER_MODE) & FLAG_RESET_MODE; ++ udelay(EC_REG_DELAY); ++ } ++ if (timeout <= 0) { ++ printk(KERN_ERR "ec rom fixup : can't check reset status.\n"); ++ ret = -EINVAL; ++ } else ++ printk(KERN_INFO "(%d/%d)reset 0xf710 : 0x%x\n", timeout, ++ EC_CMD_TIMEOUT - timeout, status); ++ ++ /* set MCU to reset mode */ ++ udelay(EC_REG_DELAY); ++ status = ec_read(REG_PXCFG); ++ status |= (1 << 0); ++ ec_write(REG_PXCFG, status); ++ udelay(EC_REG_DELAY); ++ ++ /* disable FWH/LPC */ ++ udelay(EC_REG_DELAY); ++ status = ec_read(REG_LPCCFG); ++ status &= ~(1 << 7); ++ ec_write(REG_LPCCFG, status); ++ udelay(EC_REG_DELAY); ++ ++ printk(KERN_INFO "entering reset mode ok..............\n"); ++ ++ out: ++ return ret; ++} ++ ++/* make ec exit from reset mode */ ++static void ec_exit_reset_mode(void) ++{ ++ unsigned char regval; ++ ++ udelay(EC_REG_DELAY); ++ regval = ec_read(REG_LPCCFG); ++ regval |= (1 << 7); ++ ec_write(REG_LPCCFG, regval); ++ regval = ec_read(REG_PXCFG); ++ regval &= ~(1 << 0); ++ ec_write(REG_PXCFG, regval); ++ printk(KERN_INFO "exit reset mode ok..................\n"); ++ ++ return; ++} ++ ++/* make ec disable WDD */ ++static void ec_disable_WDD(void) ++{ ++ unsigned char status; ++ ++ udelay(EC_REG_DELAY); ++ status = ec_read(REG_WDTCFG); ++ ec_write(REG_WDTPF, 0x03); ++ ec_write(REG_WDTCFG, (status & 0x80) | 0x48); ++ printk(KERN_INFO "Disable WDD ok..................\n"); ++ ++ return; ++} ++ ++/* make ec enable WDD */ ++static void ec_enable_WDD(void) ++{ ++ unsigned char status; ++ ++ udelay(EC_REG_DELAY); ++ status = ec_read(REG_WDTCFG); ++ ec_write(REG_WDT, 0x28); /* set WDT 5sec(0x28) */ ++ ec_write(REG_WDTCFG, (status & 0x80) | 0x03); ++ printk(KERN_INFO "Enable WDD ok..................\n"); ++ ++ return; ++} ++ ++/* make ec goto idle mode */ ++static int ec_init_idle_mode(void) ++{ ++ int timeout; ++ unsigned char status = 0; ++ int ret = 0; ++ ++ ec_query_seq(CMD_INIT_IDLE_MODE); ++ ++ /* make the action take active */ ++ timeout = EC_CMD_TIMEOUT; ++ status = ec_read(REG_POWER_MODE) & FLAG_IDLE_MODE; ++ while (timeout--) { ++ if (status) { ++ udelay(EC_REG_DELAY); ++ break; ++ } ++ status = ec_read(REG_POWER_MODE) & FLAG_IDLE_MODE; ++ udelay(EC_REG_DELAY); ++ } ++ if (timeout <= 0) { ++ printk(KERN_ERR "ec rom fixup : can't check out the status.\n"); ++ ret = -EINVAL; ++ } else ++ printk(KERN_INFO "(%d/%d)0xf710 : 0x%x\n", timeout, ++ EC_CMD_TIMEOUT - timeout, ec_read(REG_POWER_MODE)); ++ ++ printk(KERN_INFO "entering idle mode ok...................\n"); ++ ++ return ret; ++} ++ ++/* make ec exit from idle mode */ ++static int ec_exit_idle_mode(void) ++{ ++ ++ ec_query_seq(CMD_EXIT_IDLE_MODE); ++ ++ printk(KERN_INFO "exit idle mode ok...................\n"); ++ ++ return 0; ++} ++ ++static int ec_instruction_cycle(void) ++{ ++ unsigned long timeout; ++ int ret = 0; ++ ++ timeout = EC_FLASH_TIMEOUT; ++ while (timeout-- >= 0) { ++ if (!(ec_read(REG_XBISPICFG) & SPICFG_SPI_BUSY)) ++ break; ++ } ++ if (timeout <= 0) { ++ printk(KERN_ERR ++ "EC_INSTRUCTION_CYCLE : timeout for check flag.\n"); ++ ret = -EINVAL; ++ goto out; ++ } ++ ++ out: ++ return ret; ++} ++ ++/* To see if the ec is in busy state or not. */ ++static inline int ec_flash_busy(unsigned long timeout) ++{ ++ /* assurance the first command be going to rom */ ++ if (ec_instruction_cycle() < 0) ++ return EC_STATE_BUSY; ++#if 1 ++ timeout = timeout / EC_MAX_DELAY_UNIT; ++ while (timeout-- > 0) { ++ /* check the rom's status of busy flag */ ++ ec_write(REG_XBISPICMD, SPICMD_READ_STATUS); ++ if (ec_instruction_cycle() < 0) ++ return EC_STATE_BUSY; ++ if ((ec_read(REG_XBISPIDAT) & 0x01) == 0x00) ++ return EC_STATE_IDLE; ++ udelay(EC_MAX_DELAY_UNIT); ++ } ++ if (timeout <= 0) { ++ printk(KERN_ERR ++ "EC_FLASH_BUSY : timeout for check rom flag.\n"); ++ return EC_STATE_BUSY; ++ } ++#else ++ /* check the rom's status of busy flag */ ++ ec_write(REG_XBISPICMD, SPICMD_READ_STATUS); ++ if (ec_instruction_cycle() < 0) ++ return EC_STATE_BUSY; ++ ++ timeout = timeout / EC_MAX_DELAY_UNIT; ++ while (timeout-- > 0) { ++ if ((ec_read(REG_XBISPIDAT) & 0x01) == 0x00) ++ return EC_STATE_IDLE; ++ udelay(EC_MAX_DELAY_UNIT); ++ } ++ if (timeout <= 0) { ++ printk(KERN_ERR ++ "EC_FLASH_BUSY : timeout for check rom flag.\n"); ++ return EC_STATE_BUSY; ++ } ++#endif ++ ++ return EC_STATE_IDLE; ++} ++ ++static int rom_instruction_cycle(unsigned char cmd) ++{ ++ unsigned long timeout = 0; ++ ++ switch (cmd) { ++ case SPICMD_READ_STATUS: ++ case SPICMD_WRITE_ENABLE: ++ case SPICMD_WRITE_DISABLE: ++ case SPICMD_READ_BYTE: ++ case SPICMD_HIGH_SPEED_READ: ++ timeout = 0; ++ break; ++ case SPICMD_WRITE_STATUS: ++ timeout = 300 * 1000; ++ break; ++ case SPICMD_BYTE_PROGRAM: ++ timeout = 5 * 1000; ++ break; ++ case SPICMD_SST_SEC_ERASE: ++ case SPICMD_SEC_ERASE: ++ timeout = 1000 * 1000; ++ break; ++ case SPICMD_SST_BLK_ERASE: ++ case SPICMD_BLK_ERASE: ++ timeout = 3 * 1000 * 1000; ++ break; ++ case SPICMD_SST_CHIP_ERASE: ++ case SPICMD_CHIP_ERASE: ++ timeout = 20 * 1000 * 1000; ++ break; ++ default: ++ timeout = EC_SPICMD_STANDARD_TIMEOUT; ++ } ++ if (timeout == 0) ++ return ec_instruction_cycle(); ++ if (timeout < EC_SPICMD_STANDARD_TIMEOUT) ++ timeout = EC_SPICMD_STANDARD_TIMEOUT; ++ ++ return ec_flash_busy(timeout); ++} ++ ++/* delay for start/stop action */ ++static void delay_spi(int n) ++{ ++ while (n--) ++ inb(EC_IO_PORT_HIGH); ++} ++ ++/* start the action to spi rom function */ ++static void ec_start_spi(void) ++{ ++ unsigned char val; ++ ++ delay_spi(SPI_FINISH_WAIT_TIME); ++ val = ec_read(REG_XBISPICFG) | SPICFG_EN_SPICMD | SPICFG_AUTO_CHECK; ++ ec_write(REG_XBISPICFG, val); ++ delay_spi(SPI_FINISH_WAIT_TIME); ++} ++ ++/* stop the action to spi rom function */ ++static void ec_stop_spi(void) ++{ ++ unsigned char val; ++ ++ delay_spi(SPI_FINISH_WAIT_TIME); ++ val = ++ ec_read(REG_XBISPICFG) & (~(SPICFG_EN_SPICMD | SPICFG_AUTO_CHECK)); ++ ec_write(REG_XBISPICFG, val); ++ delay_spi(SPI_FINISH_WAIT_TIME); ++} ++ ++/* read one byte from xbi interface */ ++static int ec_read_byte(unsigned int addr, unsigned char *byte) ++{ ++ int ret = 0; ++ ++ /* enable spicmd writing. */ ++ ec_start_spi(); ++ ++ /* enable write spi flash */ ++ ec_write(REG_XBISPICMD, SPICMD_WRITE_ENABLE); ++ if (rom_instruction_cycle(SPICMD_WRITE_ENABLE) == EC_STATE_BUSY) { ++ printk(KERN_ERR "EC_READ_BYTE : SPICMD_WRITE_ENABLE failed.\n"); ++ ret = -EINVAL; ++ goto out; ++ } ++ ++ /* write the address */ ++ ec_write(REG_XBISPIA2, (addr & 0xff0000) >> 16); ++ ec_write(REG_XBISPIA1, (addr & 0x00ff00) >> 8); ++ ec_write(REG_XBISPIA0, (addr & 0x0000ff) >> 0); ++ /* start action */ ++ ec_write(REG_XBISPICMD, SPICMD_HIGH_SPEED_READ); ++ if (rom_instruction_cycle(SPICMD_HIGH_SPEED_READ) == EC_STATE_BUSY) { ++ printk(KERN_ERR ++ "EC_READ_BYTE : SPICMD_HIGH_SPEED_READ failed.\n"); ++ ret = -EINVAL; ++ goto out; ++ } ++ ++ *byte = ec_read(REG_XBISPIDAT); ++ ++ out: ++ /* disable spicmd writing. */ ++ ec_stop_spi(); ++ ++ return ret; ++} ++ ++/* write one byte to ec rom */ ++static int ec_write_byte(unsigned int addr, unsigned char byte) ++{ ++ int ret = 0; ++ ++ /* enable spicmd writing. */ ++ ec_start_spi(); ++ ++ /* enable write spi flash */ ++ ec_write(REG_XBISPICMD, SPICMD_WRITE_ENABLE); ++ if (rom_instruction_cycle(SPICMD_WRITE_ENABLE) == EC_STATE_BUSY) { ++ printk(KERN_ERR ++ "EC_WRITE_BYTE : SPICMD_WRITE_ENABLE failed.\n"); ++ ret = -EINVAL; ++ goto out; ++ } ++ ++ /* write the address */ ++ ec_write(REG_XBISPIA2, (addr & 0xff0000) >> 16); ++ ec_write(REG_XBISPIA1, (addr & 0x00ff00) >> 8); ++ ec_write(REG_XBISPIA0, (addr & 0x0000ff) >> 0); ++ ec_write(REG_XBISPIDAT, byte); ++ /* start action */ ++ ec_write(REG_XBISPICMD, SPICMD_BYTE_PROGRAM); ++ if (rom_instruction_cycle(SPICMD_BYTE_PROGRAM) == EC_STATE_BUSY) { ++ printk(KERN_ERR ++ "EC_WRITE_BYTE : SPICMD_BYTE_PROGRAM failed.\n"); ++ ret = -EINVAL; ++ goto out; ++ } ++ ++ out: ++ /* disable spicmd writing. */ ++ ec_stop_spi(); ++ ++ return ret; ++} ++ ++/* unprotect SPI ROM */ ++/* EC_ROM_unprotect function code */ ++static int EC_ROM_unprotect(void) ++{ ++ unsigned char status; ++ ++ /* enable write spi flash */ ++ ec_write(REG_XBISPICMD, SPICMD_WRITE_ENABLE); ++ if (rom_instruction_cycle(SPICMD_WRITE_ENABLE) == EC_STATE_BUSY) { ++ printk(KERN_ERR ++ "EC_UNIT_ERASE : SPICMD_WRITE_ENABLE failed.\n"); ++ return 1; ++ } ++ ++ /* unprotect the status register of rom */ ++ ec_write(REG_XBISPICMD, SPICMD_READ_STATUS); ++ if (rom_instruction_cycle(SPICMD_READ_STATUS) == EC_STATE_BUSY) { ++ printk(KERN_ERR "EC_UNIT_ERASE : SPICMD_READ_STATUS failed.\n"); ++ return 1; ++ } ++ status = ec_read(REG_XBISPIDAT); ++ ec_write(REG_XBISPIDAT, status & 0x02); ++ if (ec_instruction_cycle() < 0) { ++ printk(KERN_ERR "EC_UNIT_ERASE : write status value failed.\n"); ++ return 1; ++ } ++ ++ ec_write(REG_XBISPICMD, SPICMD_WRITE_STATUS); ++ if (rom_instruction_cycle(SPICMD_WRITE_STATUS) == EC_STATE_BUSY) { ++ printk(KERN_ERR ++ "EC_UNIT_ERASE : SPICMD_WRITE_STATUS failed.\n"); ++ return 1; ++ } ++ ++ /* enable write spi flash */ ++ ec_write(REG_XBISPICMD, SPICMD_WRITE_ENABLE); ++ if (rom_instruction_cycle(SPICMD_WRITE_ENABLE) == EC_STATE_BUSY) { ++ printk(KERN_ERR ++ "EC_UNIT_ERASE : SPICMD_WRITE_ENABLE failed.\n"); ++ return 1; ++ } ++ ++ return 0; ++} ++ ++/* erase one block or chip or sector as needed */ ++static int ec_unit_erase(unsigned char erase_cmd, unsigned int addr) ++{ ++ unsigned char status; ++ int ret = 0, i = 0; ++ int unprotect_count = 3; ++ int check_flag = 0; ++ ++ /* enable spicmd writing. */ ++ ec_start_spi(); ++ ++#ifdef EC_ROM_PROTECTION ++ /* added for re-check SPICMD_READ_STATUS */ ++ while (unprotect_count-- > 0) { ++ if (EC_ROM_unprotect()) { ++ ret = -EINVAL; ++ goto out; ++ } ++ ++ /* first time:500ms --> 5.5sec -->10.5sec */ ++ for (i = 0; i < ((2 - unprotect_count) * 100 + 10); i++) ++ udelay(50000); ++ ec_write(REG_XBISPICMD, SPICMD_READ_STATUS); ++ if (rom_instruction_cycle(SPICMD_READ_STATUS) ++ == EC_STATE_BUSY) { ++ printk(KERN_ERR ++ "EC_PROGRAM_ROM : SPICMD_READ_STATUS failed.\n"); ++ } else { ++ status = ec_read(REG_XBISPIDAT); ++ printk(KERN_INFO "Read unprotect status : 0x%x\n", ++ status); ++ if ((status & 0x1C) == 0x00) { ++ printk(KERN_INFO ++ "Read unprotect status OK1 : 0x%x\n", ++ status & 0x1C); ++ check_flag = 1; ++ break; ++ } ++ } ++ } ++ ++ if (!check_flag) { ++ printk(KERN_INFO "SPI ROM unprotect fail.\n"); ++ return 1; ++ } ++#endif ++ ++ /* block address fill */ ++ if (erase_cmd == SPICMD_BLK_ERASE) { ++ ec_write(REG_XBISPIA2, (addr & 0x00ff0000) >> 16); ++ ec_write(REG_XBISPIA1, (addr & 0x0000ff00) >> 8); ++ ec_write(REG_XBISPIA0, (addr & 0x000000ff) >> 0); ++ } ++ ++ /* erase the whole chip first */ ++ ec_write(REG_XBISPICMD, erase_cmd); ++ if (rom_instruction_cycle(erase_cmd) == EC_STATE_BUSY) { ++ printk(KERN_ERR "EC_UNIT_ERASE : erase failed.\n"); ++ ret = -EINVAL; ++ goto out; ++ } ++ ++ out: ++ /* disable spicmd writing. */ ++ ec_stop_spi(); ++ ++ return ret; ++} ++ ++/* update the whole rom content with H/W mode ++ * PLEASE USING ec_unit_erase() FIRSTLY ++ */ ++static int ec_program_rom(struct ec_info *info, int flag) ++{ ++ unsigned int addr = 0; ++ unsigned long size = 0; ++ unsigned char *ptr = NULL; ++ unsigned char data; ++ unsigned char val = 0; ++ int ret = 0; ++ int i, j; ++ unsigned char status; ++ ++ /* modify for program serial No. ++ * set IE_START_ADDR & use idle mode, ++ * disable WDD ++ */ ++ if (flag == PROGRAM_FLAG_ROM) { ++ ret = ec_init_reset_mode(); ++ addr = info->start_addr + EC_START_ADDR; ++ printk(KERN_INFO "PROGRAM_FLAG_ROM..............\n"); ++ } else if (flag == PROGRAM_FLAG_IE) { ++ ret = ec_init_idle_mode(); ++ ec_disable_WDD(); ++ addr = info->start_addr + IE_START_ADDR; ++ printk(KERN_INFO "PROGRAM_FLAG_IE..............\n"); ++ } else { ++ return 0; ++ } ++ ++ if (ret < 0) { ++ if (flag == PROGRAM_FLAG_IE) ++ ec_enable_WDD(); ++ return ret; ++ } ++ ++ size = info->size; ++ ptr = info->buf; ++ printk(KERN_INFO "starting update ec ROM..............\n"); ++ ++ ret = ec_unit_erase(SPICMD_BLK_ERASE, addr); ++ if (ret) { ++ printk(KERN_ERR "program ec : erase block failed.\n"); ++ goto out; ++ } ++ printk(KERN_ERR "program ec : erase block OK.\n"); ++ ++ i = 0; ++ while (i < size) { ++ data = *(ptr + i); ++ ec_write_byte(addr, data); ++ ec_read_byte(addr, &val); ++ if (val != data) { ++ ec_write_byte(addr, data); ++ ec_read_byte(addr, &val); ++ if (val != data) { ++ printk(KERN_INFO ++ "EC : Second flash program failed at:\t"); ++ printk(KERN_INFO ++ "addr : 0x%x, source : 0x%x, dest: 0x%x\n", ++ addr, data, val); ++ printk(KERN_INFO "This should not happen... STOP\n"); ++ break; ++ } ++ } ++ i++; ++ addr++; ++ } ++ ++#ifdef EC_ROM_PROTECTION ++ /* we should start spi access firstly */ ++ ec_start_spi(); ++ ++ /* enable write spi flash */ ++ ec_write(REG_XBISPICMD, SPICMD_WRITE_ENABLE); ++ if (rom_instruction_cycle(SPICMD_WRITE_ENABLE) == EC_STATE_BUSY) { ++ printk(KERN_ERR ++ "EC_PROGRAM_ROM : SPICMD_WRITE_ENABLE failed.\n"); ++ goto out1; ++ } ++ ++ /* protect the status register of rom */ ++ ec_write(REG_XBISPICMD, SPICMD_READ_STATUS); ++ if (rom_instruction_cycle(SPICMD_READ_STATUS) == EC_STATE_BUSY) { ++ printk(KERN_ERR ++ "EC_PROGRAM_ROM : SPICMD_READ_STATUS failed.\n"); ++ goto out1; ++ } ++ status = ec_read(REG_XBISPIDAT); ++ ++ ec_write(REG_XBISPIDAT, status | 0x1C); ++ if (ec_instruction_cycle() < 0) { ++ printk(KERN_ERR ++ "EC_PROGRAM_ROM : write status value failed.\n"); ++ goto out1; ++ } ++ ++ ec_write(REG_XBISPICMD, SPICMD_WRITE_STATUS); ++ if (rom_instruction_cycle(SPICMD_WRITE_STATUS) == EC_STATE_BUSY) { ++ printk(KERN_ERR ++ "EC_PROGRAM_ROM : SPICMD_WRITE_STATUS failed.\n"); ++ goto out1; ++ } ++#endif ++ ++ /* disable the write action to spi rom */ ++ ec_write(REG_XBISPICMD, SPICMD_WRITE_DISABLE); ++ if (rom_instruction_cycle(SPICMD_WRITE_DISABLE) == EC_STATE_BUSY) { ++ printk(KERN_ERR ++ "EC_PROGRAM_ROM : SPICMD_WRITE_DISABLE failed.\n"); ++ goto out1; ++ } ++ ++ out1: ++ /* we should stop spi access firstly */ ++ ec_stop_spi(); ++ out: ++ /* for security */ ++ for (j = 0; j < 2000; j++) ++ udelay(1000); ++ ++ /* modify for program serial No. ++ * after program No exit idle mode ++ * and enable WDD ++ */ ++ if (flag == PROGRAM_FLAG_ROM) { ++ /* exit from the reset mode */ ++ ec_exit_reset_mode(); ++ } else { ++ /* ec exit from idle mode */ ++ ret = ec_exit_idle_mode(); ++ ec_enable_WDD(); ++ if (ret < 0) ++ return ret; ++ } ++ ++ return 0; ++} ++ ++/* ioctl */ ++static int misc_ioctl(struct inode *inode, struct file *filp, u_int cmd, ++ u_long arg) ++{ ++ struct ec_info ecinfo; ++ void __user *ptr = (void __user *)arg; ++ struct ec_reg *ecreg = (struct ec_reg *)(filp->private_data); ++ int ret = 0; ++ ++ switch (cmd) { ++ case IOCTL_RDREG: ++ ret = copy_from_user(ecreg, ptr, sizeof(struct ec_reg)); ++ if (ret) { ++ printk(KERN_ERR "reg read : copy from user error.\n"); ++ return -EFAULT; ++ } ++ if ((ecreg->addr > EC_MAX_REGADDR) ++ || (ecreg->addr < EC_MIN_REGADDR)) { ++ printk(KERN_ERR ++ "reg read : out of register address range.\n"); ++ return -EINVAL; ++ } ++ ecreg->val = ec_read(ecreg->addr); ++ ret = copy_to_user(ptr, ecreg, sizeof(struct ec_reg)); ++ if (ret) { ++ printk(KERN_ERR "reg read : copy to user error.\n"); ++ return -EFAULT; ++ } ++ break; ++ case IOCTL_WRREG: ++ ret = copy_from_user(ecreg, ptr, sizeof(struct ec_reg)); ++ if (ret) { ++ printk(KERN_ERR "reg write : copy from user error.\n"); ++ return -EFAULT; ++ } ++ if ((ecreg->addr > EC_MAX_REGADDR) ++ || (ecreg->addr < EC_MIN_REGADDR)) { ++ printk(KERN_ERR ++ "reg write : out of register address range.\n"); ++ return -EINVAL; ++ } ++ ec_write(ecreg->addr, ecreg->val); ++ break; ++ case IOCTL_READ_EC: ++ ret = copy_from_user(ecreg, ptr, sizeof(struct ec_reg)); ++ if (ret) { ++ printk(KERN_ERR "spi read : copy from user error.\n"); ++ return -EFAULT; ++ } ++ if ((ecreg->addr > EC_RAM_ADDR) ++ && (ecreg->addr < EC_MAX_REGADDR)) { ++ printk(KERN_ERR ++ "spi read : out of register address range.\n"); ++ return -EINVAL; ++ } ++ ec_read_byte(ecreg->addr, &(ecreg->val)); ++ ret = copy_to_user(ptr, ecreg, sizeof(struct ec_reg)); ++ if (ret) { ++ printk(KERN_ERR "spi read : copy to user error.\n"); ++ return -EFAULT; ++ } ++ break; ++ case IOCTL_PROGRAM_IE: ++ ecinfo.start_addr = EC_START_ADDR; ++ ecinfo.size = EC_CONTENT_MAX_SIZE; ++ ecinfo.buf = (u8 *) kmalloc(ecinfo.size, GFP_KERNEL); ++ if (ecinfo.buf == NULL) { ++ printk(KERN_ERR "program ie : kmalloc failed.\n"); ++ return -ENOMEM; ++ } ++ ret = copy_from_user(ecinfo.buf, (u8 *) ptr, ecinfo.size); ++ if (ret) { ++ printk(KERN_ERR "program ie : copy from user error.\n"); ++ kfree(ecinfo.buf); ++ ecinfo.buf = NULL; ++ return -EFAULT; ++ } ++ ++ /* use ec_program_rom to write serial No */ ++ ec_program_rom(&ecinfo, PROGRAM_FLAG_IE); ++ ++ kfree(ecinfo.buf); ++ ecinfo.buf = NULL; ++ break; ++ case IOCTL_PROGRAM_EC: ++ ecinfo.start_addr = EC_START_ADDR; ++ if (get_user((ecinfo.size), (u32 *) ptr)) { ++ printk(KERN_ERR "program ec : get user error.\n"); ++ return -EFAULT; ++ } ++ if ((ecinfo.size) > EC_CONTENT_MAX_SIZE) { ++ printk(KERN_ERR "program ec : size out of limited.\n"); ++ return -EINVAL; ++ } ++ ecinfo.buf = (u8 *) kmalloc(ecinfo.size, GFP_KERNEL); ++ if (ecinfo.buf == NULL) { ++ printk(KERN_ERR "program ec : kmalloc failed.\n"); ++ return -ENOMEM; ++ } ++ ret = copy_from_user(ecinfo.buf, ((u8 *) ptr + 4), ecinfo.size); ++ if (ret) { ++ printk(KERN_ERR "program ec : copy from user error.\n"); ++ kfree(ecinfo.buf); ++ ecinfo.buf = NULL; ++ return -EFAULT; ++ } ++ ++ ec_program_rom(&ecinfo, PROGRAM_FLAG_ROM); ++ ++ kfree(ecinfo.buf); ++ ecinfo.buf = NULL; ++ break; ++ ++ default: ++ break; ++ } ++ ++ return 0; ++} ++ ++static long misc_compat_ioctl(struct file *file, unsigned int cmd, ++ unsigned long arg) ++{ ++ return misc_ioctl(file->f_dentry->d_inode, file, cmd, arg); ++} ++ ++static int misc_open(struct inode *inode, struct file *filp) ++{ ++ struct ec_reg *ecreg = NULL; ++ ecreg = kmalloc(sizeof(struct ec_reg), GFP_KERNEL); ++ if (ecreg) ++ filp->private_data = ecreg; ++ ++ return ecreg ? 0 : -ENOMEM; ++} ++ ++static int misc_release(struct inode *inode, struct file *filp) ++{ ++ struct ec_reg *ecreg = (struct ec_reg *)(filp->private_data); ++ ++ filp->private_data = NULL; ++ kfree(ecreg); ++ ++ return 0; ++} ++ ++static const struct file_operations ecmisc_fops = { ++ .open = misc_open, ++ .release = misc_release, ++ .read = NULL, ++ .write = NULL, ++#ifdef CONFIG_64BIT ++ .compat_ioctl = misc_compat_ioctl, ++#else ++ .ioctl = misc_ioctl, ++#endif ++}; ++ ++static struct miscdevice ecmisc_device = { ++ .minor = MISC_DYNAMIC_MINOR, ++ .name = EC_MISC_DEV, ++ .fops = &ecmisc_fops ++}; ++ ++static int __init ecmisc_init(void) ++{ ++ int ret; ++ ++ printk(KERN_INFO "EC misc device init.\n"); ++ ret = misc_register(&ecmisc_device); ++ ++ return ret; ++} ++ ++static void __exit ecmisc_exit(void) ++{ ++ printk(KERN_INFO "EC misc device exit.\n"); ++ misc_deregister(&ecmisc_device); ++} ++ ++module_init(ecmisc_init); ++module_exit(ecmisc_exit); ++ ++MODULE_AUTHOR("liujl <liujl@lemote.com>"); ++MODULE_DESCRIPTION("Driver for flushing/dumping ROM of EC on YeeLoong laptop"); ++MODULE_LICENSE("GPL"); +diff -Nur linux-2.6.33/drivers/platform/mips/yeeloong_laptop.c linux-lemote/drivers/platform/mips/yeeloong_laptop.c +--- linux-2.6.33/drivers/platform/mips/yeeloong_laptop.c 1970-01-01 01:00:00.000000000 +0100 ++++ linux-lemote/drivers/platform/mips/yeeloong_laptop.c 2010-03-06 16:43:22.000000000 +0100 +@@ -0,0 +1,1194 @@ ++/* ++ * Driver for YeeLoong laptop extras ++ * ++ * Copyright (C) 2009 Lemote Inc. ++ * Author: Wu Zhangjin <wuzhangjin@gmail.com>, Liu Junliang <liujl@lemote.com> ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License version 2 as ++ * published by the Free Software Foundation. ++ */ ++ ++#include <linux/err.h> ++#include <linux/platform_device.h> ++#include <linux/backlight.h> /* for backlight subdriver */ ++#include <linux/fb.h> ++#include <linux/hwmon.h> /* for hwmon subdriver */ ++#include <linux/hwmon-sysfs.h> ++#include <linux/video_output.h> /* for video output subdriver */ ++#include <linux/input.h> /* for hotkey subdriver */ ++#include <linux/input/sparse-keymap.h> ++#include <linux/interrupt.h> ++#include <linux/delay.h> ++#include <linux/power_supply.h> /* for AC & Battery subdriver */ ++ ++#include <cs5536/cs5536.h> ++ ++#include <loongson.h> /* for loongson_cmdline */ ++#include <ec_kb3310b.h> ++ ++/* common function */ ++#define EC_VER_LEN 64 ++ ++static int ec_ver_small_than(char *version) ++{ ++ char *p, ec_ver[EC_VER_LEN]; ++ ++ p = strstr(loongson_cmdline, "EC_VER="); ++ if (!p) ++ memset(ec_ver, 0, EC_VER_LEN); ++ else { ++ strncpy(ec_ver, p, EC_VER_LEN); ++ p = strstr(ec_ver, " "); ++ if (p) ++ *p = '\0'; ++ } ++ ++ /* Seems EC(>=PQ1D26) does this job for us, we can not do it again, ++ * otherwise, the brightness will not resume to the normal level! */ ++ if (strncasecmp(ec_ver, version, 64) < 0) ++ return 1; ++ return 0; ++} ++ ++/* backlight subdriver */ ++#define MAX_BRIGHTNESS 8 ++ ++static int yeeloong_set_brightness(struct backlight_device *bd) ++{ ++ unsigned int level, current_level; ++ static unsigned int old_level; ++ ++ level = (bd->props.fb_blank == FB_BLANK_UNBLANK && ++ bd->props.power == FB_BLANK_UNBLANK) ? ++ bd->props.brightness : 0; ++ ++ level = SENSORS_LIMIT(level, 0, MAX_BRIGHTNESS); ++ ++ /* Avoid to modify the brightness when EC is tuning it */ ++ if (old_level != level) { ++ current_level = ec_read(REG_DISPLAY_BRIGHTNESS); ++ if (old_level == current_level) ++ ec_write(REG_DISPLAY_BRIGHTNESS, level); ++ old_level = level; ++ } ++ ++ return 0; ++} ++ ++static int yeeloong_get_brightness(struct backlight_device *bd) ++{ ++ return ec_read(REG_DISPLAY_BRIGHTNESS); ++} ++ ++static struct backlight_ops backlight_ops = { ++ .get_brightness = yeeloong_get_brightness, ++ .update_status = yeeloong_set_brightness, ++}; ++ ++static struct backlight_device *yeeloong_backlight_dev; ++ ++static int yeeloong_backlight_init(void) ++{ ++ int ret; ++ ++ yeeloong_backlight_dev = backlight_device_register("backlight0", NULL, ++ NULL, &backlight_ops); ++ ++ if (IS_ERR(yeeloong_backlight_dev)) { ++ ret = PTR_ERR(yeeloong_backlight_dev); ++ yeeloong_backlight_dev = NULL; ++ return ret; ++ } ++ ++ yeeloong_backlight_dev->props.max_brightness = MAX_BRIGHTNESS; ++ yeeloong_backlight_dev->props.brightness = ++ yeeloong_get_brightness(yeeloong_backlight_dev); ++ backlight_update_status(yeeloong_backlight_dev); ++ ++ return 0; ++} ++ ++static void yeeloong_backlight_exit(void) ++{ ++ if (yeeloong_backlight_dev) { ++ backlight_device_unregister(yeeloong_backlight_dev); ++ yeeloong_backlight_dev = NULL; ++ } ++} ++ ++/* AC & Battery subdriver */ ++ ++static struct power_supply yeeloong_ac, yeeloong_bat; ++ ++#define AC_OFFLINE 0 ++#define AC_ONLINE 1 ++ ++static int yeeloong_get_ac_props(struct power_supply *psy, ++ enum power_supply_property psp, ++ union power_supply_propval *val) ++{ ++ switch (psp) { ++ case POWER_SUPPLY_PROP_ONLINE: ++ val->intval = ((ec_read(REG_BAT_POWER)) & BIT_BAT_POWER_ACIN) ? ++ AC_ONLINE : AC_OFFLINE; ++ break; ++ default: ++ return -EINVAL; ++ } ++ ++ return 0; ++} ++ ++static enum power_supply_property yeeloong_ac_props[] = { ++ POWER_SUPPLY_PROP_ONLINE, ++}; ++ ++static struct power_supply yeeloong_ac = { ++ .name = "yeeloong-ac", ++ .type = POWER_SUPPLY_TYPE_MAINS, ++ .properties = yeeloong_ac_props, ++ .num_properties = ARRAY_SIZE(yeeloong_ac_props), ++ .get_property = yeeloong_get_ac_props, ++}; ++ ++#define BAT_CAP_CRITICAL 5 ++#define BAT_CAP_HIGH 99 ++ ++#define get_bat_info(type) \ ++ ((ec_read(REG_BAT_##type##_HIGH) << 8) | \ ++ (ec_read(REG_BAT_##type##_LOW))) ++ ++static int yeeloong_bat_get_ex_property(enum power_supply_property psp, ++ union power_supply_propval *val) ++{ ++ int bat_in, curr_cap, cap_level, status, charge, health; ++ ++ status = ec_read(REG_BAT_STATUS); ++ bat_in = status & BIT_BAT_STATUS_IN; ++ curr_cap = get_bat_info(RELATIVE_CAP); ++ if (status & BIT_BAT_STATUS_FULL) ++ curr_cap = 100; ++ ++ switch (psp) { ++ case POWER_SUPPLY_PROP_PRESENT: ++ val->intval = bat_in; ++ break; ++ case POWER_SUPPLY_PROP_CAPACITY: ++ val->intval = curr_cap; ++ break; ++ case POWER_SUPPLY_PROP_CAPACITY_LEVEL: ++ cap_level = POWER_SUPPLY_CAPACITY_LEVEL_NORMAL; ++ if (status & BIT_BAT_STATUS_LOW) { ++ cap_level = POWER_SUPPLY_CAPACITY_LEVEL_LOW; ++ if (curr_cap <= BAT_CAP_CRITICAL) ++ cap_level = ++ POWER_SUPPLY_CAPACITY_LEVEL_CRITICAL; ++ } else if (status & BIT_BAT_STATUS_FULL) { ++ cap_level = POWER_SUPPLY_CAPACITY_LEVEL_FULL; ++ if (curr_cap >= BAT_CAP_HIGH) ++ cap_level = POWER_SUPPLY_CAPACITY_LEVEL_HIGH; ++ } else if (status & BIT_BAT_STATUS_DESTROY) ++ cap_level = POWER_SUPPLY_CAPACITY_LEVEL_UNKNOWN; ++ val->intval = cap_level; ++ break; ++ case POWER_SUPPLY_PROP_TIME_TO_EMPTY_NOW: ++ /* seconds */ ++ val->intval = bat_in ? (curr_cap - 3) * 54 + 142 : 00; ++ break; ++ case POWER_SUPPLY_PROP_STATUS: ++ if (!bat_in) ++ charge = POWER_SUPPLY_STATUS_UNKNOWN; ++ else { ++ if (status & BIT_BAT_STATUS_FULL) { ++ val->intval = POWER_SUPPLY_STATUS_FULL; ++ break; ++ } ++ ++ charge = ec_read(REG_BAT_CHARGE); ++ if (charge & FLAG_BAT_CHARGE_DISCHARGE) ++ charge = POWER_SUPPLY_STATUS_DISCHARGING; ++ else if (charge & FLAG_BAT_CHARGE_CHARGE) ++ charge = POWER_SUPPLY_STATUS_CHARGING; ++ else ++ charge = POWER_SUPPLY_STATUS_NOT_CHARGING; ++ } ++ val->intval = charge; ++ break; ++ case POWER_SUPPLY_PROP_HEALTH: ++ if (!bat_in) /* no battery present */ ++ health = POWER_SUPPLY_HEALTH_UNKNOWN; ++ else { /* Assume it is good */ ++ health = POWER_SUPPLY_HEALTH_GOOD; ++ if (status & ++ (BIT_BAT_STATUS_DESTROY | BIT_BAT_STATUS_LOW)) ++ health = POWER_SUPPLY_HEALTH_DEAD; ++ if (ec_read(REG_BAT_CHARGE_STATUS) & ++ BIT_BAT_CHARGE_STATUS_OVERTEMP) ++ health = POWER_SUPPLY_HEALTH_OVERHEAT; ++ } ++ val->intval = health; ++ break; ++ default: ++ return -EINVAL; ++ } ++ return 0; ++} ++ ++static int get_battery_temp(void) ++{ ++ int value; ++ ++ value = get_bat_info(TEMPERATURE); ++ ++ return value * 1000; ++} ++ ++static int get_battery_current(void) ++{ ++ s16 value; ++ ++ value = get_bat_info(CURRENT); ++ ++ return -value; ++} ++ ++static int get_battery_voltage(void) ++{ ++ int value; ++ ++ value = get_bat_info(VOLTAGE); ++ ++ return value; ++} ++ ++static int yeeloong_get_bat_props(struct power_supply *psy, ++ enum power_supply_property psp, ++ union power_supply_propval *val) ++{ ++ switch (psp) { ++ /* Fixed information */ ++ case POWER_SUPPLY_PROP_VOLTAGE_MAX_DESIGN: ++ val->intval = get_bat_info(DESIGN_CAP) * 1000; /* mV -> µV */ ++ break; ++ case POWER_SUPPLY_PROP_CHARGE_FULL_DESIGN: ++ val->intval = get_bat_info(DESIGN_VOL) * 1000; /* mA -> µA */ ++ break; ++ case POWER_SUPPLY_PROP_CHARGE_FULL: ++ val->intval = get_bat_info(FULLCHG_CAP) * 1000; /* µA */ ++ break; ++ case POWER_SUPPLY_PROP_MANUFACTURER: ++ val->strval = (ec_read(REG_BAT_VENDOR) == ++ FLAG_BAT_VENDOR_SANYO) ? "SANYO" : "SIMPLO"; ++ break; ++ /* Dynamic information */ ++ case POWER_SUPPLY_PROP_CURRENT_NOW: ++ val->intval = get_battery_current() * 1000; /* mA -> µA */ ++ break; ++ case POWER_SUPPLY_PROP_VOLTAGE_NOW: ++ val->intval = get_battery_voltage() * 1000; /* mV -> µV */ ++ break; ++ case POWER_SUPPLY_PROP_TEMP: ++ val->intval = get_battery_temp(); /* Celcius */ ++ break; ++ /* Dynamic but related information */ ++ default: ++ return yeeloong_bat_get_ex_property(psp, val); ++ } ++ ++ return 0; ++} ++ ++static enum power_supply_property yeeloong_bat_props[] = { ++ POWER_SUPPLY_PROP_STATUS, ++ POWER_SUPPLY_PROP_PRESENT, ++ POWER_SUPPLY_PROP_VOLTAGE_MAX_DESIGN, ++ POWER_SUPPLY_PROP_CHARGE_FULL_DESIGN, ++ POWER_SUPPLY_PROP_CURRENT_NOW, ++ POWER_SUPPLY_PROP_VOLTAGE_NOW, ++ POWER_SUPPLY_PROP_HEALTH, ++ POWER_SUPPLY_PROP_TIME_TO_EMPTY_NOW, ++ POWER_SUPPLY_PROP_CAPACITY, ++ POWER_SUPPLY_PROP_CAPACITY_LEVEL, ++ POWER_SUPPLY_PROP_TEMP, ++ POWER_SUPPLY_PROP_MANUFACTURER, ++}; ++ ++static struct power_supply yeeloong_bat = { ++ .name = "yeeloong-bat", ++ .type = POWER_SUPPLY_TYPE_BATTERY, ++ .properties = yeeloong_bat_props, ++ .num_properties = ARRAY_SIZE(yeeloong_bat_props), ++ .get_property = yeeloong_get_bat_props, ++}; ++ ++static int ac_bat_initialized; ++ ++static int yeeloong_bat_init(void) ++{ ++ int ret; ++ ++ ret = power_supply_register(NULL, &yeeloong_ac); ++ if (ret) ++ return ret; ++ ret = power_supply_register(NULL, &yeeloong_bat); ++ if (ret) { ++ power_supply_unregister(&yeeloong_ac); ++ return ret; ++ } ++ ac_bat_initialized = 1; ++ ++ return 0; ++} ++ ++static void yeeloong_bat_exit(void) ++{ ++ ac_bat_initialized = 0; ++ ++ power_supply_unregister(&yeeloong_ac); ++ power_supply_unregister(&yeeloong_bat); ++} ++/* hwmon subdriver */ ++ ++#define MIN_FAN_SPEED 0 ++#define MAX_FAN_SPEED 3 ++ ++static int get_fan_pwm_enable(void) ++{ ++ int level, mode; ++ ++ level = ec_read(REG_FAN_SPEED_LEVEL); ++ mode = ec_read(REG_FAN_AUTO_MAN_SWITCH); ++ ++ if (level == MAX_FAN_SPEED && mode == BIT_FAN_MANUAL) ++ mode = 0; ++ else if (mode == BIT_FAN_MANUAL) ++ mode = 1; ++ else ++ mode = 2; ++ ++ return mode; ++} ++ ++static void set_fan_pwm_enable(int mode) ++{ ++ switch (mode) { ++ case 0: ++ /* fullspeed */ ++ ec_write(REG_FAN_AUTO_MAN_SWITCH, BIT_FAN_MANUAL); ++ ec_write(REG_FAN_SPEED_LEVEL, MAX_FAN_SPEED); ++ break; ++ case 1: ++ ec_write(REG_FAN_AUTO_MAN_SWITCH, BIT_FAN_MANUAL); ++ break; ++ case 2: ++ ec_write(REG_FAN_AUTO_MAN_SWITCH, BIT_FAN_AUTO); ++ break; ++ default: ++ break; ++ } ++} ++ ++static int get_fan_pwm(void) ++{ ++ return ec_read(REG_FAN_SPEED_LEVEL); ++} ++ ++static void set_fan_pwm(int value) ++{ ++ int mode; ++ ++ mode = ec_read(REG_FAN_AUTO_MAN_SWITCH); ++ if (mode != BIT_FAN_MANUAL) ++ return; ++ ++ value = SENSORS_LIMIT(value, 0, 3); ++ ++ /* We must ensure the fan is on */ ++ if (value > 0) ++ ec_write(REG_FAN_CONTROL, BIT_FAN_CONTROL_ON); ++ ++ ec_write(REG_FAN_SPEED_LEVEL, value); ++} ++ ++static int get_fan_rpm(void) ++{ ++ int value; ++ ++ value = FAN_SPEED_DIVIDER / ++ (((ec_read(REG_FAN_SPEED_HIGH) & 0x0f) << 8) | ++ ec_read(REG_FAN_SPEED_LOW)); ++ ++ return value; ++} ++ ++static int get_cpu_temp(void) ++{ ++ s8 value; ++ ++ value = ec_read(REG_TEMPERATURE_VALUE); ++ ++ return value * 1000; ++} ++ ++static int get_cpu_temp_max(void) ++{ ++ return 60 * 1000; ++} ++ ++static int get_battery_temp_alarm(void) ++{ ++ int status; ++ ++ status = (ec_read(REG_BAT_CHARGE_STATUS) & ++ BIT_BAT_CHARGE_STATUS_OVERTEMP); ++ ++ return !!status; ++} ++ ++static ssize_t store_sys_hwmon(void (*set) (int), const char *buf, size_t count) ++{ ++ int ret; ++ unsigned long value; ++ ++ if (!count) ++ return 0; ++ ++ ret = strict_strtoul(buf, 10, &value); ++ if (ret) ++ return ret; ++ ++ set(value); ++ ++ return count; ++} ++ ++static ssize_t show_sys_hwmon(int (*get) (void), char *buf) ++{ ++ return sprintf(buf, "%d\n", get()); ++} ++ ++#define CREATE_SENSOR_ATTR(_name, _mode, _set, _get) \ ++ static ssize_t show_##_name(struct device *dev, \ ++ struct device_attribute *attr, \ ++ char *buf) \ ++ { \ ++ return show_sys_hwmon(_set, buf); \ ++ } \ ++ static ssize_t store_##_name(struct device *dev, \ ++ struct device_attribute *attr, \ ++ const char *buf, size_t count) \ ++ { \ ++ return store_sys_hwmon(_get, buf, count); \ ++ } \ ++ static SENSOR_DEVICE_ATTR(_name, _mode, show_##_name, store_##_name, 0); ++ ++CREATE_SENSOR_ATTR(fan1_input, S_IRUGO, get_fan_rpm, NULL); ++CREATE_SENSOR_ATTR(pwm1, S_IRUGO | S_IWUSR, get_fan_pwm, set_fan_pwm); ++CREATE_SENSOR_ATTR(pwm1_enable, S_IRUGO | S_IWUSR, get_fan_pwm_enable, ++ set_fan_pwm_enable); ++CREATE_SENSOR_ATTR(temp1_input, S_IRUGO, get_cpu_temp, NULL); ++CREATE_SENSOR_ATTR(temp1_max, S_IRUGO, get_cpu_temp_max, NULL); ++CREATE_SENSOR_ATTR(temp2_input, S_IRUGO, get_battery_temp, NULL); ++CREATE_SENSOR_ATTR(temp2_max_alarm, S_IRUGO, get_battery_temp_alarm, NULL); ++CREATE_SENSOR_ATTR(curr1_input, S_IRUGO, get_battery_current, NULL); ++CREATE_SENSOR_ATTR(in1_input, S_IRUGO, get_battery_voltage, NULL); ++ ++static ssize_t ++show_name(struct device *dev, struct device_attribute *attr, char *buf) ++{ ++ return sprintf(buf, "yeeloong\n"); ++} ++ ++static SENSOR_DEVICE_ATTR(name, S_IRUGO, show_name, NULL, 0); ++ ++static struct attribute *hwmon_attributes[] = { ++ &sensor_dev_attr_pwm1.dev_attr.attr, ++ &sensor_dev_attr_pwm1_enable.dev_attr.attr, ++ &sensor_dev_attr_fan1_input.dev_attr.attr, ++ &sensor_dev_attr_temp1_input.dev_attr.attr, ++ &sensor_dev_attr_temp1_max.dev_attr.attr, ++ &sensor_dev_attr_temp2_input.dev_attr.attr, ++ &sensor_dev_attr_temp2_max_alarm.dev_attr.attr, ++ &sensor_dev_attr_curr1_input.dev_attr.attr, ++ &sensor_dev_attr_in1_input.dev_attr.attr, ++ &sensor_dev_attr_name.dev_attr.attr, ++ NULL ++}; ++ ++static struct attribute_group hwmon_attribute_group = { ++ .attrs = hwmon_attributes ++}; ++ ++static struct device *yeeloong_hwmon_dev; ++ ++static int yeeloong_hwmon_init(void) ++{ ++ int ret; ++ ++ yeeloong_hwmon_dev = hwmon_device_register(NULL); ++ if (IS_ERR(yeeloong_hwmon_dev)) { ++ pr_err("Fail to register yeeloong hwmon device\n"); ++ yeeloong_hwmon_dev = NULL; ++ return PTR_ERR(yeeloong_hwmon_dev); ++ } ++ ret = sysfs_create_group(&yeeloong_hwmon_dev->kobj, ++ &hwmon_attribute_group); ++ if (ret) { ++ hwmon_device_unregister(yeeloong_hwmon_dev); ++ yeeloong_hwmon_dev = NULL; ++ return ret; ++ } ++ /* ensure fan is set to auto mode */ ++ set_fan_pwm_enable(2); ++ ++ return 0; ++} ++ ++static void yeeloong_hwmon_exit(void) ++{ ++ if (yeeloong_hwmon_dev) { ++ sysfs_remove_group(&yeeloong_hwmon_dev->kobj, ++ &hwmon_attribute_group); ++ hwmon_device_unregister(yeeloong_hwmon_dev); ++ yeeloong_hwmon_dev = NULL; ++ } ++} ++ ++/* video output subdriver */ ++ ++static int lcd_video_output_get(struct output_device *od) ++{ ++ return ec_read(REG_DISPLAY_LCD); ++} ++ ++#define LCD 0 ++#define CRT 1 ++ ++static void display_vo_set(int display, int on) ++{ ++ int addr; ++ unsigned long value; ++ ++ addr = (display == LCD) ? 0x31 : 0x21; ++ ++ outb(addr, 0x3c4); ++ value = inb(0x3c5); ++ ++ if (display == LCD) ++ value |= (on ? 0x03 : 0x02); ++ else { ++ if (on) ++ clear_bit(7, &value); ++ else ++ set_bit(7, &value); ++ } ++ ++ outb(addr, 0x3c4); ++ outb(value, 0x3c5); ++} ++ ++static int lcd_video_output_set(struct output_device *od) ++{ ++ unsigned long status; ++ ++ status = !!od->request_state; ++ ++ display_vo_set(LCD, status); ++ ec_write(REG_BACKLIGHT_CTRL, status); ++ ++ return 0; ++} ++ ++static struct output_properties lcd_output_properties = { ++ .set_state = lcd_video_output_set, ++ .get_status = lcd_video_output_get, ++}; ++ ++static int crt_video_output_get(struct output_device *od) ++{ ++ return ec_read(REG_CRT_DETECT); ++} ++ ++static int crt_video_output_set(struct output_device *od) ++{ ++ unsigned long status; ++ ++ status = !!od->request_state; ++ ++ if (ec_read(REG_CRT_DETECT) == BIT_CRT_DETECT_PLUG) ++ display_vo_set(CRT, status); ++ ++ return 0; ++} ++ ++static struct output_properties crt_output_properties = { ++ .set_state = crt_video_output_set, ++ .get_status = crt_video_output_get, ++}; ++ ++static struct output_device *lcd_output_dev, *crt_output_dev; ++ ++static void yeeloong_lcd_vo_set(int status) ++{ ++ if (ec_ver_small_than("EC_VER=PQ1D27")) { ++ lcd_output_dev->request_state = status; ++ lcd_video_output_set(lcd_output_dev); ++ } ++} ++ ++static void yeeloong_crt_vo_set(int status) ++{ ++ crt_output_dev->request_state = status; ++ crt_video_output_set(crt_output_dev); ++} ++ ++static int yeeloong_vo_init(void) ++{ ++ int ret; ++ ++ /* Register video output device: lcd, crt */ ++ lcd_output_dev = video_output_register("LCD", NULL, NULL, ++ &lcd_output_properties); ++ ++ if (IS_ERR(lcd_output_dev)) { ++ ret = PTR_ERR(lcd_output_dev); ++ lcd_output_dev = NULL; ++ return ret; ++ } ++ /* Ensure LCD is on by default */ ++ yeeloong_lcd_vo_set(BIT_DISPLAY_LCD_ON); ++ ++ crt_output_dev = video_output_register("CRT", NULL, NULL, ++ &crt_output_properties); ++ ++ if (IS_ERR(crt_output_dev)) { ++ ret = PTR_ERR(crt_output_dev); ++ crt_output_dev = NULL; ++ return ret; ++ } ++ ++ /* Turn off CRT by default, and will be enabled when the CRT ++ * connectting event reported by SCI */ ++ yeeloong_crt_vo_set(BIT_CRT_DETECT_UNPLUG); ++ ++ return 0; ++} ++ ++static void yeeloong_vo_exit(void) ++{ ++ if (lcd_output_dev) { ++ video_output_unregister(lcd_output_dev); ++ lcd_output_dev = NULL; ++ } ++ if (crt_output_dev) { ++ video_output_unregister(crt_output_dev); ++ crt_output_dev = NULL; ++ } ++} ++ ++/* hotkey subdriver */ ++ ++static struct input_dev *yeeloong_hotkey_dev; ++ ++static const struct key_entry yeeloong_keymap[] = { ++ {KE_SW, EVENT_LID, { SW_LID } }, ++ {KE_KEY, EVENT_CAMERA, { KEY_CAMERA } }, /* Fn + ESC */ ++ {KE_KEY, EVENT_SLEEP, { KEY_SLEEP } }, /* Fn + F1 */ ++ {KE_KEY, EVENT_DISPLAY_TOGGLE, { KEY_SWITCHVIDEOMODE } }, /* Fn + F3 */ ++ {KE_KEY, EVENT_AUDIO_MUTE, { KEY_MUTE } }, /* Fn + F4 */ ++ {KE_KEY, EVENT_WLAN, { KEY_WLAN } }, /* Fn + F5 */ ++ {KE_KEY, EVENT_DISPLAY_BRIGHTNESS, { KEY_BRIGHTNESSUP } }, /* Fn + up */ ++ {KE_KEY, EVENT_DISPLAY_BRIGHTNESS, { KEY_BRIGHTNESSDOWN } }, /* Fn + down */ ++ {KE_KEY, EVENT_AUDIO_VOLUME, { KEY_VOLUMEUP } }, /* Fn + right */ ++ {KE_KEY, EVENT_AUDIO_VOLUME, { KEY_VOLUMEDOWN } }, /* Fn + left */ ++ {KE_END, 0} ++}; ++ ++static struct key_entry *get_event_key_entry(int event, int status) ++{ ++ struct key_entry *ke; ++ static int old_brightness_status = -1; ++ static int old_volume_status = -1; ++ ++ ke = sparse_keymap_entry_from_scancode(yeeloong_hotkey_dev, event); ++ if (!ke) ++ return NULL; ++ ++ switch (event) { ++ case EVENT_DISPLAY_BRIGHTNESS: ++ /* current status > old one, means up */ ++ if ((status < old_brightness_status) || (0 == status)) ++ ke++; ++ old_brightness_status = status; ++ break; ++ case EVENT_AUDIO_VOLUME: ++ if ((status < old_volume_status) || (0 == status)) ++ ke++; ++ old_volume_status = status; ++ break; ++ default: ++ break; ++ } ++ ++ return ke; ++} ++ ++static int report_lid_switch(int status) ++{ ++ input_report_switch(yeeloong_hotkey_dev, SW_LID, !status); ++ input_sync(yeeloong_hotkey_dev); ++ ++ return status; ++} ++ ++static int crt_detect_handler(int status) ++{ ++ if (status) { ++ yeeloong_crt_vo_set(BIT_CRT_DETECT_PLUG); ++ yeeloong_lcd_vo_set(BIT_DISPLAY_LCD_OFF); ++ } else { ++ yeeloong_lcd_vo_set(BIT_DISPLAY_LCD_ON); ++ yeeloong_crt_vo_set(BIT_CRT_DETECT_UNPLUG); ++ } ++ return status; ++} ++ ++static int black_screen_handler(int status) ++{ ++ if (ec_ver_small_than("EC_VER=PQ1D26")) ++ yeeloong_lcd_vo_set(status); ++ ++ return status; ++} ++ ++static int display_toggle_handler(int status) ++{ ++ static int video_output_status; ++ ++ /* Only enable switch video output button ++ * when CRT is connected */ ++ if (ec_read(REG_CRT_DETECT) == BIT_CRT_DETECT_UNPLUG) ++ return 0; ++ /* 0. no CRT connected: LCD on, CRT off ++ * 1. BOTH on ++ * 2. LCD off, CRT on ++ * 3. BOTH off ++ * 4. LCD on, CRT off ++ */ ++ video_output_status++; ++ if (video_output_status > 4) ++ video_output_status = 1; ++ ++ switch (video_output_status) { ++ case 1: ++ yeeloong_lcd_vo_set(BIT_DISPLAY_LCD_ON); ++ yeeloong_crt_vo_set(BIT_CRT_DETECT_PLUG); ++ break; ++ case 2: ++ yeeloong_lcd_vo_set(BIT_DISPLAY_LCD_OFF); ++ yeeloong_crt_vo_set(BIT_CRT_DETECT_PLUG); ++ break; ++ case 3: ++ yeeloong_lcd_vo_set(BIT_DISPLAY_LCD_OFF); ++ yeeloong_crt_vo_set(BIT_CRT_DETECT_UNPLUG); ++ break; ++ case 4: ++ yeeloong_lcd_vo_set(BIT_DISPLAY_LCD_ON); ++ yeeloong_crt_vo_set(BIT_CRT_DETECT_UNPLUG); ++ break; ++ default: ++ /* Ensure LCD is on */ ++ yeeloong_lcd_vo_set(BIT_DISPLAY_LCD_ON); ++ break; ++ } ++ return video_output_status; ++} ++ ++static int camera_handler(int status) ++{ ++ int value; ++ ++ value = ec_read(REG_CAMERA_CONTROL); ++ ec_write(REG_CAMERA_CONTROL, value | (1 << 1)); ++ ++ return status; ++} ++ ++static int usb2_handler(int status) ++{ ++ pr_emerg("USB2 Over Current occurred\n"); ++ ++ return status; ++} ++ ++static int usb0_handler(int status) ++{ ++ pr_emerg("USB0 Over Current occurred\n"); ++ ++ return status; ++} ++ ++static int ac_bat_handler(int status) ++{ ++ if (ac_bat_initialized) { ++ power_supply_changed(&yeeloong_ac); ++ power_supply_changed(&yeeloong_bat); ++ } ++ return status; ++} ++ ++static void do_event_action(int event) ++{ ++ sci_handler handler; ++ int reg, status; ++ struct key_entry *ke; ++ ++ reg = 0; ++ handler = NULL; ++ ++ switch (event) { ++ case EVENT_LID: ++ reg = REG_LID_DETECT; ++ break; ++ case EVENT_DISPLAY_TOGGLE: ++ handler = display_toggle_handler; ++ break; ++ case EVENT_CRT_DETECT: ++ reg = REG_CRT_DETECT; ++ handler = crt_detect_handler; ++ break; ++ case EVENT_CAMERA: ++ reg = REG_CAMERA_STATUS; ++ handler = camera_handler; ++ break; ++ case EVENT_USB_OC2: ++ reg = REG_USB2_FLAG; ++ handler = usb2_handler; ++ break; ++ case EVENT_USB_OC0: ++ reg = REG_USB0_FLAG; ++ handler = usb0_handler; ++ break; ++ case EVENT_BLACK_SCREEN: ++ reg = REG_DISPLAY_LCD; ++ handler = black_screen_handler; ++ break; ++ case EVENT_AUDIO_MUTE: ++ reg = REG_AUDIO_MUTE; ++ break; ++ case EVENT_DISPLAY_BRIGHTNESS: ++ reg = REG_DISPLAY_BRIGHTNESS; ++ break; ++ case EVENT_AUDIO_VOLUME: ++ reg = REG_AUDIO_VOLUME; ++ break; ++ case EVENT_AC_BAT: ++ handler = ac_bat_handler; ++ break; ++ default: ++ break; ++ } ++ ++ if (reg != 0) ++ status = ec_read(reg); ++ ++ if (handler != NULL) ++ status = handler(status); ++ ++ pr_info("%s: event: %d status: %d\n", __func__, event, status); ++ ++ /* Report current key to user-space */ ++ ke = get_event_key_entry(event, status); ++ if (ke) { ++ if (ke->keycode == SW_LID) ++ report_lid_switch(status); ++ else ++ sparse_keymap_report_entry(yeeloong_hotkey_dev, ke, 1, ++ true); ++ } ++} ++ ++/* ++ * SCI(system control interrupt) main interrupt routine ++ * ++ * We will do the query and get event number together so the interrupt routine ++ * should be longer than 120us now at least 3ms elpase for it. ++ */ ++static irqreturn_t sci_irq_handler(int irq, void *dev_id) ++{ ++ int ret, event; ++ ++ if (SCI_IRQ_NUM != irq) ++ return IRQ_NONE; ++ ++ /* Query the event number */ ++ ret = ec_query_event_num(); ++ if (ret < 0) ++ return IRQ_NONE; ++ ++ event = ec_get_event_num(); ++ if (event < EVENT_START || event > EVENT_END) ++ return IRQ_NONE; ++ ++ /* Execute corresponding actions */ ++ do_event_action(event); ++ ++ return IRQ_HANDLED; ++} ++ ++/* ++ * Config and init some msr and gpio register properly. ++ */ ++static int sci_irq_init(void) ++{ ++ u32 hi, lo; ++ u32 gpio_base; ++ unsigned long flags; ++ int ret; ++ ++ /* Get gpio base */ ++ _rdmsr(DIVIL_MSR_REG(DIVIL_LBAR_GPIO), &hi, &lo); ++ gpio_base = lo & 0xff00; ++ ++ /* Filter the former kb3310 interrupt for security */ ++ ret = ec_query_event_num(); ++ if (ret) ++ return ret; ++ ++ /* For filtering next number interrupt */ ++ udelay(10000); ++ ++ /* Set gpio native registers and msrs for GPIO27 SCI EVENT PIN ++ * gpio : ++ * input, pull-up, no-invert, event-count and value 0, ++ * no-filter, no edge mode ++ * gpio27 map to Virtual gpio0 ++ * msr : ++ * no primary and lpc ++ * Unrestricted Z input to IG10 from Virtual gpio 0. ++ */ ++ local_irq_save(flags); ++ _rdmsr(0x80000024, &hi, &lo); ++ lo &= ~(1 << 10); ++ _wrmsr(0x80000024, hi, lo); ++ _rdmsr(0x80000025, &hi, &lo); ++ lo &= ~(1 << 10); ++ _wrmsr(0x80000025, hi, lo); ++ _rdmsr(0x80000023, &hi, &lo); ++ lo |= (0x0a << 0); ++ _wrmsr(0x80000023, hi, lo); ++ local_irq_restore(flags); ++ ++ /* Set gpio27 as sci interrupt ++ * ++ * input, pull-up, no-fliter, no-negedge, invert ++ * the sci event is just about 120us ++ */ ++ asm(".set noreorder\n"); ++ /* input enable */ ++ outl(0x00000800, (gpio_base | 0xA0)); ++ /* revert the input */ ++ outl(0x00000800, (gpio_base | 0xA4)); ++ /* event-int enable */ ++ outl(0x00000800, (gpio_base | 0xB8)); ++ asm(".set reorder\n"); ++ ++ return 0; ++} ++ ++static struct irqaction sci_irqaction = { ++ .handler = sci_irq_handler, ++ .name = "sci", ++ .flags = IRQF_SHARED, ++}; ++ ++static int yeeloong_hotkey_init(void) ++{ ++ int ret; ++ ++ ret = sci_irq_init(); ++ if (ret) ++ return -EFAULT; ++ ++ ret = setup_irq(SCI_IRQ_NUM, &sci_irqaction); ++ if (ret) ++ return -EFAULT; ++ ++ yeeloong_hotkey_dev = input_allocate_device(); ++ ++ if (!yeeloong_hotkey_dev) { ++ remove_irq(SCI_IRQ_NUM, &sci_irqaction); ++ return -ENOMEM; ++ } ++ ++ yeeloong_hotkey_dev->name = "HotKeys"; ++ yeeloong_hotkey_dev->phys = "button/input0"; ++ yeeloong_hotkey_dev->id.bustype = BUS_HOST; ++ yeeloong_hotkey_dev->dev.parent = NULL; ++ ++ ret = sparse_keymap_setup(yeeloong_hotkey_dev, yeeloong_keymap, NULL); ++ if (ret) { ++ pr_err("Fail to setup input device keymap\n"); ++ input_free_device(yeeloong_hotkey_dev); ++ return ret; ++ } ++ ++ ret = input_register_device(yeeloong_hotkey_dev); ++ if (ret) { ++ sparse_keymap_free(yeeloong_hotkey_dev); ++ input_free_device(yeeloong_hotkey_dev); ++ return ret; ++ } ++ ++ /* Update the current status of LID */ ++ report_lid_switch(BIT_LID_DETECT_ON); ++ ++#ifdef CONFIG_LOONGSON_SUSPEND ++ /* Install the real yeeloong_report_lid_status for pm.c */ ++ yeeloong_report_lid_status = report_lid_switch; ++#endif ++ ++ return 0; ++} ++ ++static void yeeloong_hotkey_exit(void) ++{ ++ /* Free irq */ ++ remove_irq(SCI_IRQ_NUM, &sci_irqaction); ++ ++#ifdef CONFIG_LOONGSON_SUSPEND ++ /* Uninstall yeeloong_report_lid_status for pm.c */ ++ if (yeeloong_report_lid_status == report_lid_switch) ++ yeeloong_report_lid_status = NULL; ++#endif ++ ++ if (yeeloong_hotkey_dev) { ++ sparse_keymap_free(yeeloong_hotkey_dev); ++ input_unregister_device(yeeloong_hotkey_dev); ++ yeeloong_hotkey_dev = NULL; ++ } ++} ++ ++#ifdef CONFIG_PM ++static void usb_ports_set(int status) ++{ ++ status = !!status; ++ ++ ec_write(REG_USB0_FLAG, status); ++ ec_write(REG_USB1_FLAG, status); ++ ec_write(REG_USB2_FLAG, status); ++} ++ ++static int yeeloong_suspend(struct device *dev) ++ ++{ ++ yeeloong_lcd_vo_set(BIT_DISPLAY_LCD_OFF); ++ yeeloong_crt_vo_set(BIT_CRT_DETECT_UNPLUG); ++ usb_ports_set(BIT_USB_FLAG_OFF); ++ ++ return 0; ++} ++ ++static int yeeloong_resume(struct device *dev) ++{ ++ yeeloong_lcd_vo_set(BIT_DISPLAY_LCD_ON); ++ yeeloong_crt_vo_set(BIT_CRT_DETECT_PLUG); ++ usb_ports_set(BIT_USB_FLAG_ON); ++ ++ return 0; ++} ++ ++static const SIMPLE_DEV_PM_OPS(yeeloong_pm_ops, yeeloong_suspend, ++ yeeloong_resume); ++#endif ++ ++static struct platform_device_id platform_device_ids[] = { ++ { ++ .name = "yeeloong_laptop", ++ }, ++ {} ++}; ++ ++MODULE_DEVICE_TABLE(platform, platform_device_ids); ++ ++static struct platform_driver platform_driver = { ++ .driver = { ++ .name = "yeeloong_laptop", ++ .owner = THIS_MODULE, ++#ifdef CONFIG_PM ++ .pm = &yeeloong_pm_ops, ++#endif ++ }, ++ .id_table = platform_device_ids, ++}; ++ ++static int __init yeeloong_init(void) ++{ ++ int ret; ++ ++ pr_info("Load YeeLoong Laptop Platform Specific Driver.\n"); ++ ++ /* Register platform stuff */ ++ ret = platform_driver_register(&platform_driver); ++ if (ret) { ++ pr_err("Fail to register yeeloong platform driver.\n"); ++ return ret; ++ } ++ ++ ret = yeeloong_backlight_init(); ++ if (ret) { ++ pr_err("Fail to register yeeloong backlight driver.\n"); ++ yeeloong_backlight_exit(); ++ return ret; ++ } ++ ++ ret = yeeloong_bat_init(); ++ if (ret) { ++ pr_err("Fail to register yeeloong battery driver.\n"); ++ yeeloong_bat_exit(); ++ return ret; ++ } ++ ++ ret = yeeloong_hwmon_init(); ++ if (ret) { ++ pr_err("Fail to register yeeloong hwmon driver.\n"); ++ yeeloong_hwmon_exit(); ++ return ret; ++ } ++ ++ ret = yeeloong_vo_init(); ++ if (ret) { ++ pr_err("Fail to register yeeloong video output driver.\n"); ++ yeeloong_vo_exit(); ++ return ret; ++ } ++ ++ ret = yeeloong_hotkey_init(); ++ if (ret) { ++ pr_err("Fail to register yeeloong hotkey driver.\n"); ++ yeeloong_hotkey_exit(); ++ return ret; ++ } ++ ++ return 0; ++} ++ ++static void __exit yeeloong_exit(void) ++{ ++ yeeloong_hotkey_exit(); ++ yeeloong_vo_exit(); ++ yeeloong_hwmon_exit(); ++ yeeloong_bat_exit(); ++ yeeloong_backlight_exit(); ++ platform_driver_unregister(&platform_driver); ++ ++ pr_info("Unload YeeLoong Platform Specific Driver.\n"); ++} ++ ++module_init(yeeloong_init); ++module_exit(yeeloong_exit); ++ ++MODULE_AUTHOR("Wu Zhangjin <wuzhangjin@gmail.com>; Liu Junliang <liujl@lemote.com>"); ++MODULE_DESCRIPTION("YeeLoong laptop driver"); ++MODULE_LICENSE("GPL"); +diff -Nur linux-2.6.33/drivers/rtc/rtc-cmos.c linux-lemote/drivers/rtc/rtc-cmos.c +--- linux-2.6.33/drivers/rtc/rtc-cmos.c 2010-02-24 19:52:17.000000000 +0100 ++++ linux-lemote/drivers/rtc/rtc-cmos.c 2010-03-06 16:43:22.000000000 +0100 +@@ -752,9 +752,8 @@ + /* FIXME teach the alarm code how to handle binary mode; + * <asm-generic/rtc.h> doesn't know 12-hour mode either. + */ +- if (is_valid_irq(rtc_irq) && +- (!(rtc_control & RTC_24H) || (rtc_control & (RTC_DM_BINARY)))) { +- dev_dbg(dev, "only 24-hr BCD mode supported\n"); ++ if (is_valid_irq(rtc_irq) && !(rtc_control & RTC_24H)) { ++ dev_dbg(dev, "only 24-hr supported\n"); + retval = -ENXIO; + goto cleanup1; + } +diff -Nur linux-2.6.33/drivers/staging/sm7xx/Kconfig linux-lemote/drivers/staging/sm7xx/Kconfig +--- linux-2.6.33/drivers/staging/sm7xx/Kconfig 2010-02-24 19:52:17.000000000 +0100 ++++ linux-lemote/drivers/staging/sm7xx/Kconfig 2010-03-06 16:43:30.000000000 +0100 +@@ -6,10 +6,3 @@ + select FB_CFB_IMAGEBLIT + help + Frame Buffer driver for the Silicon Motion SM7XX serial graphic card. +- +-config FB_SM7XX_ACCEL +- bool "Siliconmotion Acceleration functions (EXPERIMENTAL)" +- depends on FB_SM7XX && EXPERIMENTAL +- help +- This will compile the Trident frame buffer device with +- acceleration functions. +diff -Nur linux-2.6.33/drivers/staging/sm7xx/smtc2d.c linux-lemote/drivers/staging/sm7xx/smtc2d.c +--- linux-2.6.33/drivers/staging/sm7xx/smtc2d.c 2010-02-24 19:52:17.000000000 +0100 ++++ linux-lemote/drivers/staging/sm7xx/smtc2d.c 1970-01-01 01:00:00.000000000 +0100 +@@ -1,979 +0,0 @@ +-/* +- * Silicon Motion SM7XX 2D drawing engine functions. +- * +- * Copyright (C) 2006 Silicon Motion Technology Corp. +- * Author: Boyod boyod.yang@siliconmotion.com.cn +- * +- * Copyright (C) 2009 Lemote, Inc. +- * Author: Wu Zhangjin, wuzj@lemote.com +- * +- * This file is subject to the terms and conditions of the GNU General Public +- * License. See the file COPYING in the main directory of this archive for +- * more details. +- * +- * Version 0.10.26192.21.01 +- * - Add PowerPC support +- * - Add 2D support for Lynx - +- * Verified on 2.6.19.2 +- * Boyod.yang <boyod.yang@siliconmotion.com.cn> +- */ +- +-unsigned char smtc_de_busy; +- +-void SMTC_write2Dreg(unsigned long nOffset, unsigned long nData) +-{ +- writel(nData, smtc_2DBaseAddress + nOffset); +-} +- +-unsigned long SMTC_read2Dreg(unsigned long nOffset) +-{ +- return readl(smtc_2DBaseAddress + nOffset); +-} +- +-void SMTC_write2Ddataport(unsigned long nOffset, unsigned long nData) +-{ +- writel(nData, smtc_2Ddataport + nOffset); +-} +- +-/********************************************************************** +- * +- * deInit +- * +- * Purpose +- * Drawing engine initialization. +- * +- **********************************************************************/ +- +-void deInit(unsigned int nModeWidth, unsigned int nModeHeight, +- unsigned int bpp) +-{ +- /* Get current power configuration. */ +- unsigned char clock; +- clock = smtc_seqr(0x21); +- +- /* initialize global 'mutex lock' variable */ +- smtc_de_busy = 0; +- +- /* Enable 2D Drawing Engine */ +- smtc_seqw(0x21, clock & 0xF8); +- +- SMTC_write2Dreg(DE_CLIP_TL, +- FIELD_VALUE(0, DE_CLIP_TL, TOP, 0) | +- FIELD_SET(0, DE_CLIP_TL, STATUS, DISABLE) | +- FIELD_SET(0, DE_CLIP_TL, INHIBIT, OUTSIDE) | +- FIELD_VALUE(0, DE_CLIP_TL, LEFT, 0)); +- +- if (bpp >= 24) { +- SMTC_write2Dreg(DE_PITCH, +- FIELD_VALUE(0, DE_PITCH, DESTINATION, +- nModeWidth * 3) | FIELD_VALUE(0, +- DE_PITCH, +- SOURCE, +- nModeWidth +- * 3)); +- } else { +- SMTC_write2Dreg(DE_PITCH, +- FIELD_VALUE(0, DE_PITCH, DESTINATION, +- nModeWidth) | FIELD_VALUE(0, +- DE_PITCH, +- SOURCE, +- nModeWidth)); +- } +- +- SMTC_write2Dreg(DE_WINDOW_WIDTH, +- FIELD_VALUE(0, DE_WINDOW_WIDTH, DESTINATION, +- nModeWidth) | FIELD_VALUE(0, +- DE_WINDOW_WIDTH, +- SOURCE, +- nModeWidth)); +- +- switch (bpp) { +- case 8: +- SMTC_write2Dreg(DE_STRETCH_FORMAT, +- FIELD_SET(0, DE_STRETCH_FORMAT, PATTERN_XY, +- NORMAL) | FIELD_VALUE(0, +- DE_STRETCH_FORMAT, +- PATTERN_Y, +- 0) | +- FIELD_VALUE(0, DE_STRETCH_FORMAT, PATTERN_X, +- 0) | FIELD_SET(0, DE_STRETCH_FORMAT, +- PIXEL_FORMAT, +- 8) | FIELD_SET(0, +- DE_STRETCH_FORMAT, +- ADDRESSING, +- XY) | +- FIELD_VALUE(0, DE_STRETCH_FORMAT, +- SOURCE_HEIGHT, 3)); +- break; +- case 24: +- SMTC_write2Dreg(DE_STRETCH_FORMAT, +- FIELD_SET(0, DE_STRETCH_FORMAT, PATTERN_XY, +- NORMAL) | FIELD_VALUE(0, +- DE_STRETCH_FORMAT, +- PATTERN_Y, +- 0) | +- FIELD_VALUE(0, DE_STRETCH_FORMAT, PATTERN_X, +- 0) | FIELD_SET(0, DE_STRETCH_FORMAT, +- PIXEL_FORMAT, +- 24) | FIELD_SET(0, +- DE_STRETCH_FORMAT, +- ADDRESSING, +- XY) | +- FIELD_VALUE(0, DE_STRETCH_FORMAT, +- SOURCE_HEIGHT, 3)); +- break; +- case 16: +- default: +- SMTC_write2Dreg(DE_STRETCH_FORMAT, +- FIELD_SET(0, DE_STRETCH_FORMAT, PATTERN_XY, +- NORMAL) | FIELD_VALUE(0, +- DE_STRETCH_FORMAT, +- PATTERN_Y, +- 0) | +- FIELD_VALUE(0, DE_STRETCH_FORMAT, PATTERN_X, +- 0) | FIELD_SET(0, DE_STRETCH_FORMAT, +- PIXEL_FORMAT, +- 16) | FIELD_SET(0, +- DE_STRETCH_FORMAT, +- ADDRESSING, +- XY) | +- FIELD_VALUE(0, DE_STRETCH_FORMAT, +- SOURCE_HEIGHT, 3)); +- break; +- } +- +- SMTC_write2Dreg(DE_MASKS, +- FIELD_VALUE(0, DE_MASKS, BYTE_MASK, 0xFFFF) | +- FIELD_VALUE(0, DE_MASKS, BIT_MASK, 0xFFFF)); +- SMTC_write2Dreg(DE_COLOR_COMPARE_MASK, +- FIELD_VALUE(0, DE_COLOR_COMPARE_MASK, MASKS, \ +- 0xFFFFFF)); +- SMTC_write2Dreg(DE_COLOR_COMPARE, +- FIELD_VALUE(0, DE_COLOR_COMPARE, COLOR, 0xFFFFFF)); +-} +- +-void deVerticalLine(unsigned long dst_base, +- unsigned long dst_pitch, +- unsigned long nX, +- unsigned long nY, +- unsigned long dst_height, unsigned long nColor) +-{ +- deWaitForNotBusy(); +- +- SMTC_write2Dreg(DE_WINDOW_DESTINATION_BASE, +- FIELD_VALUE(0, DE_WINDOW_DESTINATION_BASE, ADDRESS, +- dst_base)); +- +- SMTC_write2Dreg(DE_PITCH, +- FIELD_VALUE(0, DE_PITCH, DESTINATION, dst_pitch) | +- FIELD_VALUE(0, DE_PITCH, SOURCE, dst_pitch)); +- +- SMTC_write2Dreg(DE_WINDOW_WIDTH, +- FIELD_VALUE(0, DE_WINDOW_WIDTH, DESTINATION, +- dst_pitch) | FIELD_VALUE(0, DE_WINDOW_WIDTH, +- SOURCE, +- dst_pitch)); +- +- SMTC_write2Dreg(DE_FOREGROUND, +- FIELD_VALUE(0, DE_FOREGROUND, COLOR, nColor)); +- +- SMTC_write2Dreg(DE_DESTINATION, +- FIELD_SET(0, DE_DESTINATION, WRAP, DISABLE) | +- FIELD_VALUE(0, DE_DESTINATION, X, nX) | +- FIELD_VALUE(0, DE_DESTINATION, Y, nY)); +- +- SMTC_write2Dreg(DE_DIMENSION, +- FIELD_VALUE(0, DE_DIMENSION, X, 1) | +- FIELD_VALUE(0, DE_DIMENSION, Y_ET, dst_height)); +- +- SMTC_write2Dreg(DE_CONTROL, +- FIELD_SET(0, DE_CONTROL, STATUS, START) | +- FIELD_SET(0, DE_CONTROL, DIRECTION, LEFT_TO_RIGHT) | +- FIELD_SET(0, DE_CONTROL, MAJOR, Y) | +- FIELD_SET(0, DE_CONTROL, STEP_X, NEGATIVE) | +- FIELD_SET(0, DE_CONTROL, STEP_Y, POSITIVE) | +- FIELD_SET(0, DE_CONTROL, LAST_PIXEL, OFF) | +- FIELD_SET(0, DE_CONTROL, COMMAND, SHORT_STROKE) | +- FIELD_SET(0, DE_CONTROL, ROP_SELECT, ROP2) | +- FIELD_VALUE(0, DE_CONTROL, ROP, 0x0C)); +- +- smtc_de_busy = 1; +-} +- +-void deHorizontalLine(unsigned long dst_base, +- unsigned long dst_pitch, +- unsigned long nX, +- unsigned long nY, +- unsigned long dst_width, unsigned long nColor) +-{ +- deWaitForNotBusy(); +- +- SMTC_write2Dreg(DE_WINDOW_DESTINATION_BASE, +- FIELD_VALUE(0, DE_WINDOW_DESTINATION_BASE, ADDRESS, +- dst_base)); +- +- SMTC_write2Dreg(DE_PITCH, +- FIELD_VALUE(0, DE_PITCH, DESTINATION, dst_pitch) | +- FIELD_VALUE(0, DE_PITCH, SOURCE, dst_pitch)); +- +- SMTC_write2Dreg(DE_WINDOW_WIDTH, +- FIELD_VALUE(0, DE_WINDOW_WIDTH, DESTINATION, +- dst_pitch) | FIELD_VALUE(0, DE_WINDOW_WIDTH, +- SOURCE, +- dst_pitch)); +- SMTC_write2Dreg(DE_FOREGROUND, +- FIELD_VALUE(0, DE_FOREGROUND, COLOR, nColor)); +- SMTC_write2Dreg(DE_DESTINATION, +- FIELD_SET(0, DE_DESTINATION, WRAP, +- DISABLE) | FIELD_VALUE(0, DE_DESTINATION, X, +- nX) | FIELD_VALUE(0, +- DE_DESTINATION, +- Y, +- nY)); +- SMTC_write2Dreg(DE_DIMENSION, +- FIELD_VALUE(0, DE_DIMENSION, X, +- dst_width) | FIELD_VALUE(0, DE_DIMENSION, +- Y_ET, 1)); +- SMTC_write2Dreg(DE_CONTROL, +- FIELD_SET(0, DE_CONTROL, STATUS, START) | FIELD_SET(0, +- DE_CONTROL, +- DIRECTION, +- RIGHT_TO_LEFT) +- | FIELD_SET(0, DE_CONTROL, MAJOR, X) | FIELD_SET(0, +- DE_CONTROL, +- STEP_X, +- POSITIVE) +- | FIELD_SET(0, DE_CONTROL, STEP_Y, +- NEGATIVE) | FIELD_SET(0, DE_CONTROL, +- LAST_PIXEL, +- OFF) | FIELD_SET(0, +- DE_CONTROL, +- COMMAND, +- SHORT_STROKE) +- | FIELD_SET(0, DE_CONTROL, ROP_SELECT, +- ROP2) | FIELD_VALUE(0, DE_CONTROL, ROP, +- 0x0C)); +- +- smtc_de_busy = 1; +-} +- +-void deLine(unsigned long dst_base, +- unsigned long dst_pitch, +- unsigned long nX1, +- unsigned long nY1, +- unsigned long nX2, unsigned long nY2, unsigned long nColor) +-{ +- unsigned long nCommand = +- FIELD_SET(0, DE_CONTROL, STATUS, START) | +- FIELD_SET(0, DE_CONTROL, DIRECTION, LEFT_TO_RIGHT) | +- FIELD_SET(0, DE_CONTROL, MAJOR, X) | +- FIELD_SET(0, DE_CONTROL, STEP_X, POSITIVE) | +- FIELD_SET(0, DE_CONTROL, STEP_Y, POSITIVE) | +- FIELD_SET(0, DE_CONTROL, LAST_PIXEL, OFF) | +- FIELD_SET(0, DE_CONTROL, ROP_SELECT, ROP2) | +- FIELD_VALUE(0, DE_CONTROL, ROP, 0x0C); +- unsigned long DeltaX; +- unsigned long DeltaY; +- +- /* Calculate delta X */ +- if (nX1 <= nX2) +- DeltaX = nX2 - nX1; +- else { +- DeltaX = nX1 - nX2; +- nCommand = FIELD_SET(nCommand, DE_CONTROL, STEP_X, NEGATIVE); +- } +- +- /* Calculate delta Y */ +- if (nY1 <= nY2) +- DeltaY = nY2 - nY1; +- else { +- DeltaY = nY1 - nY2; +- nCommand = FIELD_SET(nCommand, DE_CONTROL, STEP_Y, NEGATIVE); +- } +- +- /* Determine the major axis */ +- if (DeltaX < DeltaY) +- nCommand = FIELD_SET(nCommand, DE_CONTROL, MAJOR, Y); +- +- /* Vertical line? */ +- if (nX1 == nX2) +- deVerticalLine(dst_base, dst_pitch, nX1, nY1, DeltaY, nColor); +- +- /* Horizontal line? */ +- else if (nY1 == nY2) +- deHorizontalLine(dst_base, dst_pitch, nX1, nY1, \ +- DeltaX, nColor); +- +- /* Diagonal line? */ +- else if (DeltaX == DeltaY) { +- deWaitForNotBusy(); +- +- SMTC_write2Dreg(DE_WINDOW_DESTINATION_BASE, +- FIELD_VALUE(0, DE_WINDOW_DESTINATION_BASE, +- ADDRESS, dst_base)); +- +- SMTC_write2Dreg(DE_PITCH, +- FIELD_VALUE(0, DE_PITCH, DESTINATION, +- dst_pitch) | FIELD_VALUE(0, +- DE_PITCH, +- SOURCE, +- dst_pitch)); +- +- SMTC_write2Dreg(DE_WINDOW_WIDTH, +- FIELD_VALUE(0, DE_WINDOW_WIDTH, DESTINATION, +- dst_pitch) | FIELD_VALUE(0, +- DE_WINDOW_WIDTH, +- SOURCE, +- dst_pitch)); +- +- SMTC_write2Dreg(DE_FOREGROUND, +- FIELD_VALUE(0, DE_FOREGROUND, COLOR, nColor)); +- +- SMTC_write2Dreg(DE_DESTINATION, +- FIELD_SET(0, DE_DESTINATION, WRAP, DISABLE) | +- FIELD_VALUE(0, DE_DESTINATION, X, 1) | +- FIELD_VALUE(0, DE_DESTINATION, Y, nY1)); +- +- SMTC_write2Dreg(DE_DIMENSION, +- FIELD_VALUE(0, DE_DIMENSION, X, 1) | +- FIELD_VALUE(0, DE_DIMENSION, Y_ET, DeltaX)); +- +- SMTC_write2Dreg(DE_CONTROL, +- FIELD_SET(nCommand, DE_CONTROL, COMMAND, +- SHORT_STROKE)); +- } +- +- /* Generic line */ +- else { +- unsigned int k1, k2, et, w; +- if (DeltaX < DeltaY) { +- k1 = 2 * DeltaX; +- et = k1 - DeltaY; +- k2 = et - DeltaY; +- w = DeltaY + 1; +- } else { +- k1 = 2 * DeltaY; +- et = k1 - DeltaX; +- k2 = et - DeltaX; +- w = DeltaX + 1; +- } +- +- deWaitForNotBusy(); +- +- SMTC_write2Dreg(DE_WINDOW_DESTINATION_BASE, +- FIELD_VALUE(0, DE_WINDOW_DESTINATION_BASE, +- ADDRESS, dst_base)); +- +- SMTC_write2Dreg(DE_PITCH, +- FIELD_VALUE(0, DE_PITCH, DESTINATION, +- dst_pitch) | FIELD_VALUE(0, +- DE_PITCH, +- SOURCE, +- dst_pitch)); +- +- SMTC_write2Dreg(DE_WINDOW_WIDTH, +- FIELD_VALUE(0, DE_WINDOW_WIDTH, DESTINATION, +- dst_pitch) | FIELD_VALUE(0, +- DE_WINDOW_WIDTH, +- SOURCE, +- dst_pitch)); +- +- SMTC_write2Dreg(DE_FOREGROUND, +- FIELD_VALUE(0, DE_FOREGROUND, COLOR, nColor)); +- +- SMTC_write2Dreg(DE_SOURCE, +- FIELD_SET(0, DE_SOURCE, WRAP, DISABLE) | +- FIELD_VALUE(0, DE_SOURCE, X_K1, k1) | +- FIELD_VALUE(0, DE_SOURCE, Y_K2, k2)); +- +- SMTC_write2Dreg(DE_DESTINATION, +- FIELD_SET(0, DE_DESTINATION, WRAP, DISABLE) | +- FIELD_VALUE(0, DE_DESTINATION, X, nX1) | +- FIELD_VALUE(0, DE_DESTINATION, Y, nY1)); +- +- SMTC_write2Dreg(DE_DIMENSION, +- FIELD_VALUE(0, DE_DIMENSION, X, w) | +- FIELD_VALUE(0, DE_DIMENSION, Y_ET, et)); +- +- SMTC_write2Dreg(DE_CONTROL, +- FIELD_SET(nCommand, DE_CONTROL, COMMAND, +- LINE_DRAW)); +- } +- +- smtc_de_busy = 1; +-} +- +-void deFillRect(unsigned long dst_base, +- unsigned long dst_pitch, +- unsigned long dst_X, +- unsigned long dst_Y, +- unsigned long dst_width, +- unsigned long dst_height, unsigned long nColor) +-{ +- deWaitForNotBusy(); +- +- SMTC_write2Dreg(DE_WINDOW_DESTINATION_BASE, +- FIELD_VALUE(0, DE_WINDOW_DESTINATION_BASE, ADDRESS, +- dst_base)); +- +- if (dst_pitch) { +- SMTC_write2Dreg(DE_PITCH, +- FIELD_VALUE(0, DE_PITCH, DESTINATION, +- dst_pitch) | FIELD_VALUE(0, +- DE_PITCH, +- SOURCE, +- dst_pitch)); +- +- SMTC_write2Dreg(DE_WINDOW_WIDTH, +- FIELD_VALUE(0, DE_WINDOW_WIDTH, DESTINATION, +- dst_pitch) | FIELD_VALUE(0, +- DE_WINDOW_WIDTH, +- SOURCE, +- dst_pitch)); +- } +- +- SMTC_write2Dreg(DE_FOREGROUND, +- FIELD_VALUE(0, DE_FOREGROUND, COLOR, nColor)); +- +- SMTC_write2Dreg(DE_DESTINATION, +- FIELD_SET(0, DE_DESTINATION, WRAP, DISABLE) | +- FIELD_VALUE(0, DE_DESTINATION, X, dst_X) | +- FIELD_VALUE(0, DE_DESTINATION, Y, dst_Y)); +- +- SMTC_write2Dreg(DE_DIMENSION, +- FIELD_VALUE(0, DE_DIMENSION, X, dst_width) | +- FIELD_VALUE(0, DE_DIMENSION, Y_ET, dst_height)); +- +- SMTC_write2Dreg(DE_CONTROL, +- FIELD_SET(0, DE_CONTROL, STATUS, START) | +- FIELD_SET(0, DE_CONTROL, DIRECTION, LEFT_TO_RIGHT) | +- FIELD_SET(0, DE_CONTROL, LAST_PIXEL, OFF) | +- FIELD_SET(0, DE_CONTROL, COMMAND, RECTANGLE_FILL) | +- FIELD_SET(0, DE_CONTROL, ROP_SELECT, ROP2) | +- FIELD_VALUE(0, DE_CONTROL, ROP, 0x0C)); +- +- smtc_de_busy = 1; +-} +- +-/********************************************************************** +- * +- * deRotatePattern +- * +- * Purpose +- * Rotate the given pattern if necessary +- * +- * Parameters +- * [in] +- * pPattern - Pointer to DE_SURFACE structure containing +- * pattern attributes +- * patternX - X position (0-7) of pattern origin +- * patternY - Y position (0-7) of pattern origin +- * +- * [out] +- * pattern_dstaddr - Pointer to pre-allocated buffer containing +- * rotated pattern +- * +- **********************************************************************/ +-void deRotatePattern(unsigned char *pattern_dstaddr, +- unsigned long pattern_src_addr, +- unsigned long pattern_BPP, +- unsigned long pattern_stride, int patternX, int patternY) +-{ +- unsigned int i; +- unsigned long pattern[PATTERN_WIDTH * PATTERN_HEIGHT]; +- unsigned int x, y; +- unsigned char *pjPatByte; +- +- if (pattern_dstaddr != NULL) { +- deWaitForNotBusy(); +- +- if (patternX || patternY) { +- /* Rotate pattern */ +- pjPatByte = (unsigned char *)pattern; +- +- switch (pattern_BPP) { +- case 8: +- { +- for (y = 0; y < 8; y++) { +- unsigned char *pjBuffer = +- pattern_dstaddr + +- ((patternY + y) & 7) * 8; +- for (x = 0; x < 8; x++) { +- pjBuffer[(patternX + +- x) & 7] = +- pjPatByte[x]; +- } +- pjPatByte += pattern_stride; +- } +- break; +- } +- +- case 16: +- { +- for (y = 0; y < 8; y++) { +- unsigned short *pjBuffer = +- (unsigned short *) +- pattern_dstaddr + +- ((patternY + y) & 7) * 8; +- for (x = 0; x < 8; x++) { +- pjBuffer[(patternX + +- x) & 7] = +- ((unsigned short *) +- pjPatByte)[x]; +- } +- pjPatByte += pattern_stride; +- } +- break; +- } +- +- case 32: +- { +- for (y = 0; y < 8; y++) { +- unsigned long *pjBuffer = +- (unsigned long *) +- pattern_dstaddr + +- ((patternY + y) & 7) * 8; +- for (x = 0; x < 8; x++) { +- pjBuffer[(patternX + +- x) & 7] = +- ((unsigned long *) +- pjPatByte)[x]; +- } +- pjPatByte += pattern_stride; +- } +- break; +- } +- } +- } else { +- /*Don't rotate,just copy pattern into pattern_dstaddr*/ +- for (i = 0; i < (pattern_BPP * 2); i++) { +- ((unsigned long *)pattern_dstaddr)[i] = +- pattern[i]; +- } +- } +- +- } +-} +- +-/********************************************************************** +- * +- * deCopy +- * +- * Purpose +- * Copy a rectangular area of the source surface to a destination surface +- * +- * Remarks +- * Source bitmap must have the same color depth (BPP) as the destination +- * bitmap. +- * +-**********************************************************************/ +-void deCopy(unsigned long dst_base, +- unsigned long dst_pitch, +- unsigned long dst_BPP, +- unsigned long dst_X, +- unsigned long dst_Y, +- unsigned long dst_width, +- unsigned long dst_height, +- unsigned long src_base, +- unsigned long src_pitch, +- unsigned long src_X, +- unsigned long src_Y, pTransparent pTransp, unsigned char nROP2) +-{ +- unsigned long nDirection = 0; +- unsigned long nTransparent = 0; +- /* Direction of ROP2 operation: +- * 1 = Left to Right, +- * (-1) = Right to Left +- */ +- unsigned long opSign = 1; +- /* xWidth is in pixels */ +- unsigned long xWidth = 192 / (dst_BPP / 8); +- unsigned long de_ctrl = 0; +- +- deWaitForNotBusy(); +- +- SMTC_write2Dreg(DE_WINDOW_DESTINATION_BASE, +- FIELD_VALUE(0, DE_WINDOW_DESTINATION_BASE, ADDRESS, +- dst_base)); +- +- SMTC_write2Dreg(DE_WINDOW_SOURCE_BASE, +- FIELD_VALUE(0, DE_WINDOW_SOURCE_BASE, ADDRESS, +- src_base)); +- +- if (dst_pitch && src_pitch) { +- SMTC_write2Dreg(DE_PITCH, +- FIELD_VALUE(0, DE_PITCH, DESTINATION, +- dst_pitch) | FIELD_VALUE(0, +- DE_PITCH, +- SOURCE, +- src_pitch)); +- +- SMTC_write2Dreg(DE_WINDOW_WIDTH, +- FIELD_VALUE(0, DE_WINDOW_WIDTH, DESTINATION, +- dst_pitch) | FIELD_VALUE(0, +- DE_WINDOW_WIDTH, +- SOURCE, +- src_pitch)); +- } +- +- /* Set transparent bits if necessary */ +- if (pTransp != NULL) { +- nTransparent = +- pTransp->match | pTransp->select | pTransp->control; +- +- /* Set color compare register */ +- SMTC_write2Dreg(DE_COLOR_COMPARE, +- FIELD_VALUE(0, DE_COLOR_COMPARE, COLOR, +- pTransp->color)); +- } +- +- /* Determine direction of operation */ +- if (src_Y < dst_Y) { +- /* +----------+ +- |S | +- | +----------+ +- | | | | +- | | | | +- +---|------+ | +- | D | +- +----------+ */ +- +- nDirection = BOTTOM_TO_TOP; +- } else if (src_Y > dst_Y) { +- /* +----------+ +- |D | +- | +----------+ +- | | | | +- | | | | +- +---|------+ | +- | S | +- +----------+ */ +- +- nDirection = TOP_TO_BOTTOM; +- } else { +- /* src_Y == dst_Y */ +- +- if (src_X <= dst_X) { +- /* +------+---+------+ +- |S | | D| +- | | | | +- | | | | +- | | | | +- +------+---+------+ */ +- +- nDirection = RIGHT_TO_LEFT; +- } else { +- /* src_X > dst_X */ +- +- /* +------+---+------+ +- |D | | S| +- | | | | +- | | | | +- | | | | +- +------+---+------+ */ +- +- nDirection = LEFT_TO_RIGHT; +- } +- } +- +- if ((nDirection == BOTTOM_TO_TOP) || (nDirection == RIGHT_TO_LEFT)) { +- src_X += dst_width - 1; +- src_Y += dst_height - 1; +- dst_X += dst_width - 1; +- dst_Y += dst_height - 1; +- opSign = (-1); +- } +- +- if (dst_BPP >= 24) { +- src_X *= 3; +- src_Y *= 3; +- dst_X *= 3; +- dst_Y *= 3; +- dst_width *= 3; +- if ((nDirection == BOTTOM_TO_TOP) +- || (nDirection == RIGHT_TO_LEFT)) { +- src_X += 2; +- dst_X += 2; +- } +- } +- +- /* Workaround for 192 byte hw bug */ +- if ((nROP2 != 0x0C) && ((dst_width * (dst_BPP / 8)) >= 192)) { +- /* +- * Perform the ROP2 operation in chunks of (xWidth * +- * dst_height) +- */ +- while (1) { +- deWaitForNotBusy(); +- +- SMTC_write2Dreg(DE_SOURCE, +- FIELD_SET(0, DE_SOURCE, WRAP, DISABLE) | +- FIELD_VALUE(0, DE_SOURCE, X_K1, src_X) | +- FIELD_VALUE(0, DE_SOURCE, Y_K2, src_Y)); +- +- SMTC_write2Dreg(DE_DESTINATION, +- FIELD_SET(0, DE_DESTINATION, WRAP, +- DISABLE) | FIELD_VALUE(0, +- DE_DESTINATION, +- X, +- dst_X) +- | FIELD_VALUE(0, DE_DESTINATION, Y, +- dst_Y)); +- +- SMTC_write2Dreg(DE_DIMENSION, +- FIELD_VALUE(0, DE_DIMENSION, X, +- xWidth) | FIELD_VALUE(0, +- DE_DIMENSION, +- Y_ET, +- dst_height)); +- +- de_ctrl = +- FIELD_VALUE(0, DE_CONTROL, ROP, +- nROP2) | nTransparent | FIELD_SET(0, +- DE_CONTROL, +- ROP_SELECT, +- ROP2) +- | FIELD_SET(0, DE_CONTROL, COMMAND, +- BITBLT) | ((nDirection == +- 1) ? FIELD_SET(0, +- DE_CONTROL, +- DIRECTION, +- RIGHT_TO_LEFT) +- : FIELD_SET(0, DE_CONTROL, +- DIRECTION, +- LEFT_TO_RIGHT)) | +- FIELD_SET(0, DE_CONTROL, STATUS, START); +- +- SMTC_write2Dreg(DE_CONTROL, de_ctrl); +- +- src_X += (opSign * xWidth); +- dst_X += (opSign * xWidth); +- dst_width -= xWidth; +- +- if (dst_width <= 0) { +- /* ROP2 operation is complete */ +- break; +- } +- +- if (xWidth > dst_width) +- xWidth = dst_width; +- } +- } else { +- deWaitForNotBusy(); +- SMTC_write2Dreg(DE_SOURCE, +- FIELD_SET(0, DE_SOURCE, WRAP, DISABLE) | +- FIELD_VALUE(0, DE_SOURCE, X_K1, src_X) | +- FIELD_VALUE(0, DE_SOURCE, Y_K2, src_Y)); +- +- SMTC_write2Dreg(DE_DESTINATION, +- FIELD_SET(0, DE_DESTINATION, WRAP, DISABLE) | +- FIELD_VALUE(0, DE_DESTINATION, X, dst_X) | +- FIELD_VALUE(0, DE_DESTINATION, Y, dst_Y)); +- +- SMTC_write2Dreg(DE_DIMENSION, +- FIELD_VALUE(0, DE_DIMENSION, X, dst_width) | +- FIELD_VALUE(0, DE_DIMENSION, Y_ET, dst_height)); +- +- de_ctrl = FIELD_VALUE(0, DE_CONTROL, ROP, nROP2) | +- nTransparent | +- FIELD_SET(0, DE_CONTROL, ROP_SELECT, ROP2) | +- FIELD_SET(0, DE_CONTROL, COMMAND, BITBLT) | +- ((nDirection == 1) ? FIELD_SET(0, DE_CONTROL, DIRECTION, +- RIGHT_TO_LEFT) +- : FIELD_SET(0, DE_CONTROL, DIRECTION, +- LEFT_TO_RIGHT)) | FIELD_SET(0, DE_CONTROL, +- STATUS, START); +- SMTC_write2Dreg(DE_CONTROL, de_ctrl); +- } +- +- smtc_de_busy = 1; +-} +- +-/* +- * This function sets the pixel format that will apply to the 2D Engine. +- */ +-void deSetPixelFormat(unsigned long bpp) +-{ +- unsigned long de_format; +- +- de_format = SMTC_read2Dreg(DE_STRETCH_FORMAT); +- +- switch (bpp) { +- case 8: +- de_format = +- FIELD_SET(de_format, DE_STRETCH_FORMAT, PIXEL_FORMAT, 8); +- break; +- default: +- case 16: +- de_format = +- FIELD_SET(de_format, DE_STRETCH_FORMAT, PIXEL_FORMAT, 16); +- break; +- case 32: +- de_format = +- FIELD_SET(de_format, DE_STRETCH_FORMAT, PIXEL_FORMAT, 32); +- break; +- } +- +- SMTC_write2Dreg(DE_STRETCH_FORMAT, de_format); +-} +- +-/* +- * System memory to Video memory monochrome expansion. +- * +- * Source is monochrome image in system memory. This function expands the +- * monochrome data to color image in video memory. +- */ +- +-long deSystemMem2VideoMemMonoBlt(const char *pSrcbuf, +- long srcDelta, +- unsigned long startBit, +- unsigned long dBase, +- unsigned long dPitch, +- unsigned long bpp, +- unsigned long dx, unsigned long dy, +- unsigned long width, unsigned long height, +- unsigned long fColor, +- unsigned long bColor, +- unsigned long rop2) { +- unsigned long bytePerPixel; +- unsigned long ulBytesPerScan; +- unsigned long ul4BytesPerScan; +- unsigned long ulBytesRemain; +- unsigned long de_ctrl = 0; +- unsigned char ajRemain[4]; +- long i, j; +- +- bytePerPixel = bpp / 8; +- +- /* Just make sure the start bit is within legal range */ +- startBit &= 7; +- +- ulBytesPerScan = (width + startBit + 7) / 8; +- ul4BytesPerScan = ulBytesPerScan & ~3; +- ulBytesRemain = ulBytesPerScan & 3; +- +- if (smtc_de_busy) +- deWaitForNotBusy(); +- +- /* +- * 2D Source Base. Use 0 for HOST Blt. +- */ +- +- SMTC_write2Dreg(DE_WINDOW_SOURCE_BASE, 0); +- +- /* +- * 2D Destination Base. +- * +- * It is an address offset (128 bit aligned) from the beginning of +- * frame buffer. +- */ +- +- SMTC_write2Dreg(DE_WINDOW_DESTINATION_BASE, dBase); +- +- if (dPitch) { +- +- /* +- * Program pitch (distance between the 1st points of two +- * adjacent lines). +- * +- * Note that input pitch is BYTE value, but the 2D Pitch +- * register uses pixel values. Need Byte to pixel convertion. +- */ +- +- SMTC_write2Dreg(DE_PITCH, +- FIELD_VALUE(0, DE_PITCH, DESTINATION, +- dPitch / +- bytePerPixel) | FIELD_VALUE(0, +- DE_PITCH, +- SOURCE, +- dPitch / +- bytePerPixel)); +- +- /* Screen Window width in Pixels. +- * +- * 2D engine uses this value to calculate the linear address in +- * frame buffer for a given point. +- */ +- +- SMTC_write2Dreg(DE_WINDOW_WIDTH, +- FIELD_VALUE(0, DE_WINDOW_WIDTH, DESTINATION, +- (dPitch / +- bytePerPixel)) | FIELD_VALUE(0, +- DE_WINDOW_WIDTH, +- SOURCE, +- (dPitch +- / +- bytePerPixel))); +- } +- /* Note: For 2D Source in Host Write, only X_K1 field is needed, and +- * Y_K2 field is not used. For mono bitmap, use startBit for X_K1. +- */ +- +- SMTC_write2Dreg(DE_SOURCE, +- FIELD_SET(0, DE_SOURCE, WRAP, DISABLE) | +- FIELD_VALUE(0, DE_SOURCE, X_K1, startBit) | +- FIELD_VALUE(0, DE_SOURCE, Y_K2, 0)); +- +- SMTC_write2Dreg(DE_DESTINATION, +- FIELD_SET(0, DE_DESTINATION, WRAP, DISABLE) | +- FIELD_VALUE(0, DE_DESTINATION, X, dx) | +- FIELD_VALUE(0, DE_DESTINATION, Y, dy)); +- +- SMTC_write2Dreg(DE_DIMENSION, +- FIELD_VALUE(0, DE_DIMENSION, X, width) | +- FIELD_VALUE(0, DE_DIMENSION, Y_ET, height)); +- +- SMTC_write2Dreg(DE_FOREGROUND, fColor); +- SMTC_write2Dreg(DE_BACKGROUND, bColor); +- +- if (bpp) +- deSetPixelFormat(bpp); +- /* Set the pixel format of the destination */ +- +- de_ctrl = FIELD_VALUE(0, DE_CONTROL, ROP, rop2) | +- FIELD_SET(0, DE_CONTROL, ROP_SELECT, ROP2) | +- FIELD_SET(0, DE_CONTROL, COMMAND, HOST_WRITE) | +- FIELD_SET(0, DE_CONTROL, HOST, MONO) | +- FIELD_SET(0, DE_CONTROL, STATUS, START); +- +- SMTC_write2Dreg(DE_CONTROL, de_ctrl | deGetTransparency()); +- +- /* Write MONO data (line by line) to 2D Engine data port */ +- for (i = 0; i < height; i++) { +- /* For each line, send the data in chunks of 4 bytes */ +- for (j = 0; j < (ul4BytesPerScan / 4); j++) +- SMTC_write2Ddataport(0, +- *(unsigned long *)(pSrcbuf + +- (j * 4))); +- +- if (ulBytesRemain) { +- memcpy(ajRemain, pSrcbuf + ul4BytesPerScan, +- ulBytesRemain); +- SMTC_write2Ddataport(0, *(unsigned long *)ajRemain); +- } +- +- pSrcbuf += srcDelta; +- } +- smtc_de_busy = 1; +- +- return 0; +-} +- +-/* +- * This function gets the transparency status from DE_CONTROL register. +- * It returns a double word with the transparent fields properly set, +- * while other fields are 0. +- */ +-unsigned long deGetTransparency(void) +-{ +- unsigned long de_ctrl; +- +- de_ctrl = SMTC_read2Dreg(DE_CONTROL); +- +- de_ctrl &= +- FIELD_MASK(DE_CONTROL_TRANSPARENCY_MATCH) | +- FIELD_MASK(DE_CONTROL_TRANSPARENCY_SELECT) | +- FIELD_MASK(DE_CONTROL_TRANSPARENCY); +- +- return de_ctrl; +-} +diff -Nur linux-2.6.33/drivers/staging/sm7xx/smtc2d.h linux-lemote/drivers/staging/sm7xx/smtc2d.h +--- linux-2.6.33/drivers/staging/sm7xx/smtc2d.h 2010-02-24 19:52:17.000000000 +0100 ++++ linux-lemote/drivers/staging/sm7xx/smtc2d.h 1970-01-01 01:00:00.000000000 +0100 +@@ -1,530 +0,0 @@ +-/* +- * Silicon Motion SM712 2D drawing engine functions. +- * +- * Copyright (C) 2006 Silicon Motion Technology Corp. +- * Author: Ge Wang, gewang@siliconmotion.com +- * +- * Copyright (C) 2009 Lemote, Inc. +- * Author: Wu Zhangjin, wuzj@lemote.com +- * +- * This file is subject to the terms and conditions of the GNU General Public +- * License. See the file COPYING in the main directory of this archive for +- * more details. +- */ +- +-#ifndef NULL +-#define NULL 0 +-#endif +- +-/* Internal macros */ +- +-#define _F_START(f) (0 ? f) +-#define _F_END(f) (1 ? f) +-#define _F_SIZE(f) (1 + _F_END(f) - _F_START(f)) +-#define _F_MASK(f) (((1ULL << _F_SIZE(f)) - 1) << _F_START(f)) +-#define _F_NORMALIZE(v, f) (((v) & _F_MASK(f)) >> _F_START(f)) +-#define _F_DENORMALIZE(v, f) (((v) << _F_START(f)) & _F_MASK(f)) +- +-/* Global macros */ +- +-#define FIELD_GET(x, reg, field) \ +-( \ +- _F_NORMALIZE((x), reg ## _ ## field) \ +-) +- +-#define FIELD_SET(x, reg, field, value) \ +-( \ +- (x & ~_F_MASK(reg ## _ ## field)) \ +- | _F_DENORMALIZE(reg ## _ ## field ## _ ## value, reg ## _ ## field) \ +-) +- +-#define FIELD_VALUE(x, reg, field, value) \ +-( \ +- (x & ~_F_MASK(reg ## _ ## field)) \ +- | _F_DENORMALIZE(value, reg ## _ ## field) \ +-) +- +-#define FIELD_CLEAR(reg, field) \ +-( \ +- ~_F_MASK(reg ## _ ## field) \ +-) +- +-/* Field Macros */ +- +-#define FIELD_START(field) (0 ? field) +-#define FIELD_END(field) (1 ? field) +-#define FIELD_SIZE(field) \ +- (1 + FIELD_END(field) - FIELD_START(field)) +- +-#define FIELD_MASK(field) \ +- (((1 << (FIELD_SIZE(field)-1)) \ +- | ((1 << (FIELD_SIZE(field)-1)) - 1)) \ +- << FIELD_START(field)) +- +-#define FIELD_NORMALIZE(reg, field) \ +- (((reg) & FIELD_MASK(field)) >> FIELD_START(field)) +- +-#define FIELD_DENORMALIZE(field, value) \ +- (((value) << FIELD_START(field)) & FIELD_MASK(field)) +- +-#define FIELD_INIT(reg, field, value) \ +- FIELD_DENORMALIZE(reg ## _ ## field, \ +- reg ## _ ## field ## _ ## value) +- +-#define FIELD_INIT_VAL(reg, field, value) \ +- (FIELD_DENORMALIZE(reg ## _ ## field, value)) +- +-#define FIELD_VAL_SET(x, r, f, v) ({ \ +- x = (x & ~FIELD_MASK(r ## _ ## f)) \ +- | FIELD_DENORMALIZE(r ## _ ## f, r ## _ ## f ## _ ## v) \ +-}) +- +-#define RGB(r, g, b) ((unsigned long)(((r) << 16) | ((g) << 8) | (b))) +- +-/* Transparent info definition */ +-typedef struct { +- unsigned long match; /* Matching pixel is OPAQUE/TRANSPARENT */ +- unsigned long select; /* Transparency controlled by SRC/DST */ +- unsigned long control; /* ENABLE/DISABLE transparency */ +- unsigned long color; /* Transparent color */ +-} Transparent, *pTransparent; +- +-#define PIXEL_DEPTH_1_BP 0 /* 1 bit per pixel */ +-#define PIXEL_DEPTH_8_BPP 1 /* 8 bits per pixel */ +-#define PIXEL_DEPTH_16_BPP 2 /* 16 bits per pixel */ +-#define PIXEL_DEPTH_32_BPP 3 /* 32 bits per pixel */ +-#define PIXEL_DEPTH_YUV422 8 /* 16 bits per pixel YUV422 */ +-#define PIXEL_DEPTH_YUV420 9 /* 16 bits per pixel YUV420 */ +- +-#define PATTERN_WIDTH 8 +-#define PATTERN_HEIGHT 8 +- +-#define TOP_TO_BOTTOM 0 +-#define BOTTOM_TO_TOP 1 +-#define RIGHT_TO_LEFT BOTTOM_TO_TOP +-#define LEFT_TO_RIGHT TOP_TO_BOTTOM +- +-/* Constants used in Transparent structure */ +-#define MATCH_OPAQUE 0x00000000 +-#define MATCH_TRANSPARENT 0x00000400 +-#define SOURCE 0x00000000 +-#define DESTINATION 0x00000200 +- +-/* 2D registers. */ +- +-#define DE_SOURCE 0x000000 +-#define DE_SOURCE_WRAP 31 : 31 +-#define DE_SOURCE_WRAP_DISABLE 0 +-#define DE_SOURCE_WRAP_ENABLE 1 +-#define DE_SOURCE_X_K1 29 : 16 +-#define DE_SOURCE_Y_K2 15 : 0 +- +-#define DE_DESTINATION 0x000004 +-#define DE_DESTINATION_WRAP 31 : 31 +-#define DE_DESTINATION_WRAP_DISABLE 0 +-#define DE_DESTINATION_WRAP_ENABLE 1 +-#define DE_DESTINATION_X 28 : 16 +-#define DE_DESTINATION_Y 15 : 0 +- +-#define DE_DIMENSION 0x000008 +-#define DE_DIMENSION_X 28 : 16 +-#define DE_DIMENSION_Y_ET 15 : 0 +- +-#define DE_CONTROL 0x00000C +-#define DE_CONTROL_STATUS 31 : 31 +-#define DE_CONTROL_STATUS_STOP 0 +-#define DE_CONTROL_STATUS_START 1 +-#define DE_CONTROL_PATTERN 30 : 30 +-#define DE_CONTROL_PATTERN_MONO 0 +-#define DE_CONTROL_PATTERN_COLOR 1 +-#define DE_CONTROL_UPDATE_DESTINATION_X 29 : 29 +-#define DE_CONTROL_UPDATE_DESTINATION_X_DISABLE 0 +-#define DE_CONTROL_UPDATE_DESTINATION_X_ENABLE 1 +-#define DE_CONTROL_QUICK_START 28 : 28 +-#define DE_CONTROL_QUICK_START_DISABLE 0 +-#define DE_CONTROL_QUICK_START_ENABLE 1 +-#define DE_CONTROL_DIRECTION 27 : 27 +-#define DE_CONTROL_DIRECTION_LEFT_TO_RIGHT 0 +-#define DE_CONTROL_DIRECTION_RIGHT_TO_LEFT 1 +-#define DE_CONTROL_MAJOR 26 : 26 +-#define DE_CONTROL_MAJOR_X 0 +-#define DE_CONTROL_MAJOR_Y 1 +-#define DE_CONTROL_STEP_X 25 : 25 +-#define DE_CONTROL_STEP_X_POSITIVE 1 +-#define DE_CONTROL_STEP_X_NEGATIVE 0 +-#define DE_CONTROL_STEP_Y 24 : 24 +-#define DE_CONTROL_STEP_Y_POSITIVE 1 +-#define DE_CONTROL_STEP_Y_NEGATIVE 0 +-#define DE_CONTROL_STRETCH 23 : 23 +-#define DE_CONTROL_STRETCH_DISABLE 0 +-#define DE_CONTROL_STRETCH_ENABLE 1 +-#define DE_CONTROL_HOST 22 : 22 +-#define DE_CONTROL_HOST_COLOR 0 +-#define DE_CONTROL_HOST_MONO 1 +-#define DE_CONTROL_LAST_PIXEL 21 : 21 +-#define DE_CONTROL_LAST_PIXEL_OFF 0 +-#define DE_CONTROL_LAST_PIXEL_ON 1 +-#define DE_CONTROL_COMMAND 20 : 16 +-#define DE_CONTROL_COMMAND_BITBLT 0 +-#define DE_CONTROL_COMMAND_RECTANGLE_FILL 1 +-#define DE_CONTROL_COMMAND_DE_TILE 2 +-#define DE_CONTROL_COMMAND_TRAPEZOID_FILL 3 +-#define DE_CONTROL_COMMAND_ALPHA_BLEND 4 +-#define DE_CONTROL_COMMAND_RLE_STRIP 5 +-#define DE_CONTROL_COMMAND_SHORT_STROKE 6 +-#define DE_CONTROL_COMMAND_LINE_DRAW 7 +-#define DE_CONTROL_COMMAND_HOST_WRITE 8 +-#define DE_CONTROL_COMMAND_HOST_READ 9 +-#define DE_CONTROL_COMMAND_HOST_WRITE_BOTTOM_UP 10 +-#define DE_CONTROL_COMMAND_ROTATE 11 +-#define DE_CONTROL_COMMAND_FONT 12 +-#define DE_CONTROL_COMMAND_TEXTURE_LOAD 15 +-#define DE_CONTROL_ROP_SELECT 15 : 15 +-#define DE_CONTROL_ROP_SELECT_ROP3 0 +-#define DE_CONTROL_ROP_SELECT_ROP2 1 +-#define DE_CONTROL_ROP2_SOURCE 14 : 14 +-#define DE_CONTROL_ROP2_SOURCE_BITMAP 0 +-#define DE_CONTROL_ROP2_SOURCE_PATTERN 1 +-#define DE_CONTROL_MONO_DATA 13 : 12 +-#define DE_CONTROL_MONO_DATA_NOT_PACKED 0 +-#define DE_CONTROL_MONO_DATA_8_PACKED 1 +-#define DE_CONTROL_MONO_DATA_16_PACKED 2 +-#define DE_CONTROL_MONO_DATA_32_PACKED 3 +-#define DE_CONTROL_REPEAT_ROTATE 11 : 11 +-#define DE_CONTROL_REPEAT_ROTATE_DISABLE 0 +-#define DE_CONTROL_REPEAT_ROTATE_ENABLE 1 +-#define DE_CONTROL_TRANSPARENCY_MATCH 10 : 10 +-#define DE_CONTROL_TRANSPARENCY_MATCH_OPAQUE 0 +-#define DE_CONTROL_TRANSPARENCY_MATCH_TRANSPARENT 1 +-#define DE_CONTROL_TRANSPARENCY_SELECT 9 : 9 +-#define DE_CONTROL_TRANSPARENCY_SELECT_SOURCE 0 +-#define DE_CONTROL_TRANSPARENCY_SELECT_DESTINATION 1 +-#define DE_CONTROL_TRANSPARENCY 8 : 8 +-#define DE_CONTROL_TRANSPARENCY_DISABLE 0 +-#define DE_CONTROL_TRANSPARENCY_ENABLE 1 +-#define DE_CONTROL_ROP 7 : 0 +- +-/* Pseudo fields. */ +- +-#define DE_CONTROL_SHORT_STROKE_DIR 27 : 24 +-#define DE_CONTROL_SHORT_STROKE_DIR_225 0 +-#define DE_CONTROL_SHORT_STROKE_DIR_135 1 +-#define DE_CONTROL_SHORT_STROKE_DIR_315 2 +-#define DE_CONTROL_SHORT_STROKE_DIR_45 3 +-#define DE_CONTROL_SHORT_STROKE_DIR_270 4 +-#define DE_CONTROL_SHORT_STROKE_DIR_90 5 +-#define DE_CONTROL_SHORT_STROKE_DIR_180 8 +-#define DE_CONTROL_SHORT_STROKE_DIR_0 10 +-#define DE_CONTROL_ROTATION 25 : 24 +-#define DE_CONTROL_ROTATION_0 0 +-#define DE_CONTROL_ROTATION_270 1 +-#define DE_CONTROL_ROTATION_90 2 +-#define DE_CONTROL_ROTATION_180 3 +- +-#define DE_PITCH 0x000010 +-#define DE_PITCH_DESTINATION 28 : 16 +-#define DE_PITCH_SOURCE 12 : 0 +- +-#define DE_FOREGROUND 0x000014 +-#define DE_FOREGROUND_COLOR 31 : 0 +- +-#define DE_BACKGROUND 0x000018 +-#define DE_BACKGROUND_COLOR 31 : 0 +- +-#define DE_STRETCH_FORMAT 0x00001C +-#define DE_STRETCH_FORMAT_PATTERN_XY 30 : 30 +-#define DE_STRETCH_FORMAT_PATTERN_XY_NORMAL 0 +-#define DE_STRETCH_FORMAT_PATTERN_XY_OVERWRITE 1 +-#define DE_STRETCH_FORMAT_PATTERN_Y 29 : 27 +-#define DE_STRETCH_FORMAT_PATTERN_X 25 : 23 +-#define DE_STRETCH_FORMAT_PIXEL_FORMAT 21 : 20 +-#define DE_STRETCH_FORMAT_PIXEL_FORMAT_8 0 +-#define DE_STRETCH_FORMAT_PIXEL_FORMAT_16 1 +-#define DE_STRETCH_FORMAT_PIXEL_FORMAT_24 3 +-#define DE_STRETCH_FORMAT_PIXEL_FORMAT_32 2 +-#define DE_STRETCH_FORMAT_ADDRESSING 19 : 16 +-#define DE_STRETCH_FORMAT_ADDRESSING_XY 0 +-#define DE_STRETCH_FORMAT_ADDRESSING_LINEAR 15 +-#define DE_STRETCH_FORMAT_SOURCE_HEIGHT 11 : 0 +- +-#define DE_COLOR_COMPARE 0x000020 +-#define DE_COLOR_COMPARE_COLOR 23 : 0 +- +-#define DE_COLOR_COMPARE_MASK 0x000024 +-#define DE_COLOR_COMPARE_MASK_MASKS 23 : 0 +- +-#define DE_MASKS 0x000028 +-#define DE_MASKS_BYTE_MASK 31 : 16 +-#define DE_MASKS_BIT_MASK 15 : 0 +- +-#define DE_CLIP_TL 0x00002C +-#define DE_CLIP_TL_TOP 31 : 16 +-#define DE_CLIP_TL_STATUS 13 : 13 +-#define DE_CLIP_TL_STATUS_DISABLE 0 +-#define DE_CLIP_TL_STATUS_ENABLE 1 +-#define DE_CLIP_TL_INHIBIT 12 : 12 +-#define DE_CLIP_TL_INHIBIT_OUTSIDE 0 +-#define DE_CLIP_TL_INHIBIT_INSIDE 1 +-#define DE_CLIP_TL_LEFT 11 : 0 +- +-#define DE_CLIP_BR 0x000030 +-#define DE_CLIP_BR_BOTTOM 31 : 16 +-#define DE_CLIP_BR_RIGHT 12 : 0 +- +-#define DE_MONO_PATTERN_LOW 0x000034 +-#define DE_MONO_PATTERN_LOW_PATTERN 31 : 0 +- +-#define DE_MONO_PATTERN_HIGH 0x000038 +-#define DE_MONO_PATTERN_HIGH_PATTERN 31 : 0 +- +-#define DE_WINDOW_WIDTH 0x00003C +-#define DE_WINDOW_WIDTH_DESTINATION 28 : 16 +-#define DE_WINDOW_WIDTH_SOURCE 12 : 0 +- +-#define DE_WINDOW_SOURCE_BASE 0x000040 +-#define DE_WINDOW_SOURCE_BASE_EXT 27 : 27 +-#define DE_WINDOW_SOURCE_BASE_EXT_LOCAL 0 +-#define DE_WINDOW_SOURCE_BASE_EXT_EXTERNAL 1 +-#define DE_WINDOW_SOURCE_BASE_CS 26 : 26 +-#define DE_WINDOW_SOURCE_BASE_CS_0 0 +-#define DE_WINDOW_SOURCE_BASE_CS_1 1 +-#define DE_WINDOW_SOURCE_BASE_ADDRESS 25 : 0 +- +-#define DE_WINDOW_DESTINATION_BASE 0x000044 +-#define DE_WINDOW_DESTINATION_BASE_EXT 27 : 27 +-#define DE_WINDOW_DESTINATION_BASE_EXT_LOCAL 0 +-#define DE_WINDOW_DESTINATION_BASE_EXT_EXTERNAL 1 +-#define DE_WINDOW_DESTINATION_BASE_CS 26 : 26 +-#define DE_WINDOW_DESTINATION_BASE_CS_0 0 +-#define DE_WINDOW_DESTINATION_BASE_CS_1 1 +-#define DE_WINDOW_DESTINATION_BASE_ADDRESS 25 : 0 +- +-#define DE_ALPHA 0x000048 +-#define DE_ALPHA_VALUE 7 : 0 +- +-#define DE_WRAP 0x00004C +-#define DE_WRAP_X 31 : 16 +-#define DE_WRAP_Y 15 : 0 +- +-#define DE_STATUS 0x000050 +-#define DE_STATUS_CSC 1 : 1 +-#define DE_STATUS_CSC_CLEAR 0 +-#define DE_STATUS_CSC_NOT_ACTIVE 0 +-#define DE_STATUS_CSC_ACTIVE 1 +-#define DE_STATUS_2D 0 : 0 +-#define DE_STATUS_2D_CLEAR 0 +-#define DE_STATUS_2D_NOT_ACTIVE 0 +-#define DE_STATUS_2D_ACTIVE 1 +- +-/* Color Space Conversion registers. */ +- +-#define CSC_Y_SOURCE_BASE 0x0000C8 +-#define CSC_Y_SOURCE_BASE_EXT 27 : 27 +-#define CSC_Y_SOURCE_BASE_EXT_LOCAL 0 +-#define CSC_Y_SOURCE_BASE_EXT_EXTERNAL 1 +-#define CSC_Y_SOURCE_BASE_CS 26 : 26 +-#define CSC_Y_SOURCE_BASE_CS_0 0 +-#define CSC_Y_SOURCE_BASE_CS_1 1 +-#define CSC_Y_SOURCE_BASE_ADDRESS 25 : 0 +- +-#define CSC_CONSTANTS 0x0000CC +-#define CSC_CONSTANTS_Y 31 : 24 +-#define CSC_CONSTANTS_R 23 : 16 +-#define CSC_CONSTANTS_G 15 : 8 +-#define CSC_CONSTANTS_B 7 : 0 +- +-#define CSC_Y_SOURCE_X 0x0000D0 +-#define CSC_Y_SOURCE_X_INTEGER 26 : 16 +-#define CSC_Y_SOURCE_X_FRACTION 15 : 3 +- +-#define CSC_Y_SOURCE_Y 0x0000D4 +-#define CSC_Y_SOURCE_Y_INTEGER 27 : 16 +-#define CSC_Y_SOURCE_Y_FRACTION 15 : 3 +- +-#define CSC_U_SOURCE_BASE 0x0000D8 +-#define CSC_U_SOURCE_BASE_EXT 27 : 27 +-#define CSC_U_SOURCE_BASE_EXT_LOCAL 0 +-#define CSC_U_SOURCE_BASE_EXT_EXTERNAL 1 +-#define CSC_U_SOURCE_BASE_CS 26 : 26 +-#define CSC_U_SOURCE_BASE_CS_0 0 +-#define CSC_U_SOURCE_BASE_CS_1 1 +-#define CSC_U_SOURCE_BASE_ADDRESS 25 : 0 +- +-#define CSC_V_SOURCE_BASE 0x0000DC +-#define CSC_V_SOURCE_BASE_EXT 27 : 27 +-#define CSC_V_SOURCE_BASE_EXT_LOCAL 0 +-#define CSC_V_SOURCE_BASE_EXT_EXTERNAL 1 +-#define CSC_V_SOURCE_BASE_CS 26 : 26 +-#define CSC_V_SOURCE_BASE_CS_0 0 +-#define CSC_V_SOURCE_BASE_CS_1 1 +-#define CSC_V_SOURCE_BASE_ADDRESS 25 : 0 +- +-#define CSC_SOURCE_DIMENSION 0x0000E0 +-#define CSC_SOURCE_DIMENSION_X 31 : 16 +-#define CSC_SOURCE_DIMENSION_Y 15 : 0 +- +-#define CSC_SOURCE_PITCH 0x0000E4 +-#define CSC_SOURCE_PITCH_Y 31 : 16 +-#define CSC_SOURCE_PITCH_UV 15 : 0 +- +-#define CSC_DESTINATION 0x0000E8 +-#define CSC_DESTINATION_WRAP 31 : 31 +-#define CSC_DESTINATION_WRAP_DISABLE 0 +-#define CSC_DESTINATION_WRAP_ENABLE 1 +-#define CSC_DESTINATION_X 27 : 16 +-#define CSC_DESTINATION_Y 11 : 0 +- +-#define CSC_DESTINATION_DIMENSION 0x0000EC +-#define CSC_DESTINATION_DIMENSION_X 31 : 16 +-#define CSC_DESTINATION_DIMENSION_Y 15 : 0 +- +-#define CSC_DESTINATION_PITCH 0x0000F0 +-#define CSC_DESTINATION_PITCH_X 31 : 16 +-#define CSC_DESTINATION_PITCH_Y 15 : 0 +- +-#define CSC_SCALE_FACTOR 0x0000F4 +-#define CSC_SCALE_FACTOR_HORIZONTAL 31 : 16 +-#define CSC_SCALE_FACTOR_VERTICAL 15 : 0 +- +-#define CSC_DESTINATION_BASE 0x0000F8 +-#define CSC_DESTINATION_BASE_EXT 27 : 27 +-#define CSC_DESTINATION_BASE_EXT_LOCAL 0 +-#define CSC_DESTINATION_BASE_EXT_EXTERNAL 1 +-#define CSC_DESTINATION_BASE_CS 26 : 26 +-#define CSC_DESTINATION_BASE_CS_0 0 +-#define CSC_DESTINATION_BASE_CS_1 1 +-#define CSC_DESTINATION_BASE_ADDRESS 25 : 0 +- +-#define CSC_CONTROL 0x0000FC +-#define CSC_CONTROL_STATUS 31 : 31 +-#define CSC_CONTROL_STATUS_STOP 0 +-#define CSC_CONTROL_STATUS_START 1 +-#define CSC_CONTROL_SOURCE_FORMAT 30 : 28 +-#define CSC_CONTROL_SOURCE_FORMAT_YUV422 0 +-#define CSC_CONTROL_SOURCE_FORMAT_YUV420I 1 +-#define CSC_CONTROL_SOURCE_FORMAT_YUV420 2 +-#define CSC_CONTROL_SOURCE_FORMAT_YVU9 3 +-#define CSC_CONTROL_SOURCE_FORMAT_IYU1 4 +-#define CSC_CONTROL_SOURCE_FORMAT_IYU2 5 +-#define CSC_CONTROL_SOURCE_FORMAT_RGB565 6 +-#define CSC_CONTROL_SOURCE_FORMAT_RGB8888 7 +-#define CSC_CONTROL_DESTINATION_FORMAT 27 : 26 +-#define CSC_CONTROL_DESTINATION_FORMAT_RGB565 0 +-#define CSC_CONTROL_DESTINATION_FORMAT_RGB8888 1 +-#define CSC_CONTROL_HORIZONTAL_FILTER 25 : 25 +-#define CSC_CONTROL_HORIZONTAL_FILTER_DISABLE 0 +-#define CSC_CONTROL_HORIZONTAL_FILTER_ENABLE 1 +-#define CSC_CONTROL_VERTICAL_FILTER 24 : 24 +-#define CSC_CONTROL_VERTICAL_FILTER_DISABLE 0 +-#define CSC_CONTROL_VERTICAL_FILTER_ENABLE 1 +-#define CSC_CONTROL_BYTE_ORDER 23 : 23 +-#define CSC_CONTROL_BYTE_ORDER_YUYV 0 +-#define CSC_CONTROL_BYTE_ORDER_UYVY 1 +- +-#define DE_DATA_PORT_501 0x110000 +-#define DE_DATA_PORT_712 0x400000 +-#define DE_DATA_PORT_722 0x6000 +- +-/* point to virtual Memory Map IO starting address */ +-extern char *smtc_RegBaseAddress; +-/* point to virtual video memory starting address */ +-extern char *smtc_VRAMBaseAddress; +-extern unsigned char smtc_de_busy; +- +-extern unsigned long memRead32(unsigned long nOffset); +-extern void memWrite32(unsigned long nOffset, unsigned long nData); +-extern unsigned long SMTC_read2Dreg(unsigned long nOffset); +- +-/* 2D functions */ +-extern void deInit(unsigned int nModeWidth, unsigned int nModeHeight, +- unsigned int bpp); +- +-extern void deWaitForNotBusy(void); +- +-extern void deVerticalLine(unsigned long dst_base, +- unsigned long dst_pitch, +- unsigned long nX, +- unsigned long nY, +- unsigned long dst_height, +- unsigned long nColor); +- +-extern void deHorizontalLine(unsigned long dst_base, +- unsigned long dst_pitch, +- unsigned long nX, +- unsigned long nY, +- unsigned long dst_width, +- unsigned long nColor); +- +-extern void deLine(unsigned long dst_base, +- unsigned long dst_pitch, +- unsigned long nX1, +- unsigned long nY1, +- unsigned long nX2, +- unsigned long nY2, +- unsigned long nColor); +- +-extern void deFillRect(unsigned long dst_base, +- unsigned long dst_pitch, +- unsigned long dst_X, +- unsigned long dst_Y, +- unsigned long dst_width, +- unsigned long dst_height, +- unsigned long nColor); +- +-extern void deRotatePattern(unsigned char *pattern_dstaddr, +- unsigned long pattern_src_addr, +- unsigned long pattern_BPP, +- unsigned long pattern_stride, +- int patternX, +- int patternY); +- +-extern void deCopy(unsigned long dst_base, +- unsigned long dst_pitch, +- unsigned long dst_BPP, +- unsigned long dst_X, +- unsigned long dst_Y, +- unsigned long dst_width, +- unsigned long dst_height, +- unsigned long src_base, +- unsigned long src_pitch, +- unsigned long src_X, +- unsigned long src_Y, +- pTransparent pTransp, +- unsigned char nROP2); +- +-/* +- * System memory to Video memory monochrome expansion. +- * +- * Source is monochrome image in system memory. This function expands the +- * monochrome data to color image in video memory. +- * +- * @pSrcbuf: pointer to start of source buffer in system memory +- * @srcDelta: Pitch value (in bytes) of the source buffer, +ive means top +- * down and -ive mean button up +- * @startBit: Mono data can start at any bit in a byte, this value should +- * be 0 to 7 +- * @dBase: Address of destination : offset in frame buffer +- * @dPitch: Pitch value of destination surface in BYTE +- * @bpp: Color depth of destination surface +- * @dx, dy: Starting coordinate of destination surface +- * @width, height: width and height of rectange in pixel value +- * @fColor,bColor: Foreground, Background color (corresponding to a 1, 0 in +- * the monochrome data) +- * @rop2: ROP value +- */ +- +-extern long deSystemMem2VideoMemMonoBlt( +- const char *pSrcbuf, +- long srcDelta, +- unsigned long startBit, +- unsigned long dBase, +- unsigned long dPitch, +- unsigned long bpp, +- unsigned long dx, unsigned long dy, +- unsigned long width, unsigned long height, +- unsigned long fColor, +- unsigned long bColor, +- unsigned long rop2); +- +-extern unsigned long deGetTransparency(void); +-extern void deSetPixelFormat(unsigned long bpp); +diff -Nur linux-2.6.33/drivers/staging/sm7xx/smtcfb.c linux-lemote/drivers/staging/sm7xx/smtcfb.c +--- linux-2.6.33/drivers/staging/sm7xx/smtcfb.c 2010-02-24 19:52:17.000000000 +0100 ++++ linux-lemote/drivers/staging/sm7xx/smtcfb.c 2010-03-06 16:43:30.000000000 +0100 +@@ -6,12 +6,14 @@ + * Boyod boyod.yang@siliconmotion.com.cn + * + * Copyright (C) 2009 Lemote, Inc. +- * Author: Wu Zhangjin, wuzj@lemote.com ++ * Author: Wu Zhangjin, wuzhangjin@gmail.com + * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file COPYING in the main directory of this archive for + * more details. + * ++ * - Remove the buggy 2D support for Lynx, 2010/01/06, Wu Zhangjin ++ * + * Version 0.10.26192.21.01 + * - Add PowerPC/Big endian support + * - Add 2D support for Lynx +@@ -45,7 +47,6 @@ + struct screen_info smtc_screen_info; + + #include "smtcfb.h" +-#include "smtc2d.h" + + #ifdef DEBUG + #define smdbg(format, arg...) printk(KERN_DEBUG format , ## arg) +@@ -107,6 +108,7 @@ + {"0x307", 1280, 1024, 8}, + + {"0x311", 640, 480, 16}, ++ {"0x313", 800, 480, 16}, + {"0x314", 800, 600, 16}, + {"0x317", 1024, 768, 16}, + {"0x31A", 1280, 1024, 16}, +@@ -120,10 +122,6 @@ + char __iomem *smtc_RegBaseAddress; /* Memory Map IO starting address */ + char __iomem *smtc_VRAMBaseAddress; /* video memory starting address */ + +-char *smtc_2DBaseAddress; /* 2D engine starting address */ +-char *smtc_2Ddataport; /* 2D data port offset */ +-short smtc_2Dacceleration; +- + static u32 colreg[17]; + static struct par_info hw; /* hardware information */ + +@@ -135,16 +133,6 @@ + + #define numSMTCchipIDs (sizeof(smtc_ChipIDs) / sizeof(u16)) + +-void deWaitForNotBusy(void) +-{ +- unsigned long i = 0x1000000; +- while (i--) { +- if ((smtc_seqr(0x16) & 0x18) == 0x10) +- break; +- } +- smtc_de_busy = 0; +-} +- + static void sm712_set_timing(struct smtcfb_info *sfb, + struct par_info *ppar_info) + { +@@ -324,7 +312,7 @@ + return chan << bf->offset; + } + +-static int smtcfb_blank(int blank_mode, struct fb_info *info) ++static int cfb_blank(int blank_mode, struct fb_info *info) + { + /* clear DPMS setting */ + switch (blank_mode) { +@@ -622,93 +610,13 @@ + } + #endif /* ! __BIG_ENDIAN */ + +-#include "smtc2d.c" +- +-void smtcfb_copyarea(struct fb_info *info, const struct fb_copyarea *area) +-{ +- struct par_info *p = (struct par_info *)info->par; +- +- if (smtc_2Dacceleration) { +- if (!area->width || !area->height) +- return; +- +- deCopy(p->BaseAddressInVRAM, 0, info->var.bits_per_pixel, +- area->dx, area->dy, area->width, area->height, +- p->BaseAddressInVRAM, 0, area->sx, area->sy, 0, 0xC); +- +- } else +- cfb_copyarea(info, area); +-} +- +-void smtcfb_fillrect(struct fb_info *info, const struct fb_fillrect *rect) +-{ +- struct par_info *p = (struct par_info *)info->par; +- +- if (smtc_2Dacceleration) { +- if (!rect->width || !rect->height) +- return; +- if (info->var.bits_per_pixel >= 24) +- deFillRect(p->BaseAddressInVRAM, 0, rect->dx * 3, +- rect->dy * 3, rect->width * 3, rect->height, +- rect->color); +- else +- deFillRect(p->BaseAddressInVRAM, 0, rect->dx, rect->dy, +- rect->width, rect->height, rect->color); +- } else +- cfb_fillrect(info, rect); +-} +- +-void smtcfb_imageblit(struct fb_info *info, const struct fb_image *image) +-{ +- struct par_info *p = (struct par_info *)info->par; +- u32 bg_col = 0, fg_col = 0; +- +- if ((smtc_2Dacceleration) && (image->depth == 1)) { +- if (smtc_de_busy) +- deWaitForNotBusy(); +- +- switch (info->var.bits_per_pixel) { +- case 8: +- bg_col = image->bg_color; +- fg_col = image->fg_color; +- break; +- case 16: +- bg_col = +- ((u32 *) (info->pseudo_palette))[image->bg_color]; +- fg_col = +- ((u32 *) (info->pseudo_palette))[image->fg_color]; +- break; +- case 32: +- bg_col = +- ((u32 *) (info->pseudo_palette))[image->bg_color]; +- fg_col = +- ((u32 *) (info->pseudo_palette))[image->fg_color]; +- break; +- } +- +- deSystemMem2VideoMemMonoBlt( +- image->data, +- image->width / 8, +- 0, +- p->BaseAddressInVRAM, +- 0, +- 0, +- image->dx, image->dy, +- image->width, image->height, +- fg_col, bg_col, +- 0x0C); +- +- } else +- cfb_imageblit(info, image); +-} +- + static struct fb_ops smtcfb_ops = { + .owner = THIS_MODULE, + .fb_setcolreg = smtc_setcolreg, +- .fb_blank = smtcfb_blank, +- .fb_fillrect = smtcfb_fillrect, +- .fb_imageblit = smtcfb_imageblit, +- .fb_copyarea = smtcfb_copyarea, ++ .fb_blank = cfb_blank, ++ .fb_fillrect = cfb_fillrect, ++ .fb_imageblit = cfb_imageblit, ++ .fb_copyarea = cfb_copyarea, + #ifdef __BIG_ENDIAN + .fb_read = smtcfb_read, + .fb_write = smtcfb_write, +@@ -772,12 +680,6 @@ + hw.height = sfb->fb.var.yres; + hw.hz = 60; + smtc_set_timing(sfb, &hw); +- if (smtc_2Dacceleration) { +- printk("2D acceleration enabled!\n"); +- /* Init smtc drawing engine */ +- deInit(sfb->fb.var.xres, sfb->fb.var.yres, +- sfb->fb.var.bits_per_pixel); +- } + } + + /* +@@ -1004,9 +906,7 @@ + #endif + hw.m_pMMIO = (smtc_RegBaseAddress = + smtc_VRAMBaseAddress + 0x00700000); +- smtc_2DBaseAddress = (hw.m_pDPR = +- smtc_VRAMBaseAddress + 0x00408000); +- smtc_2Ddataport = smtc_VRAMBaseAddress + DE_DATA_PORT_712; ++ hw.m_pDPR = smtc_VRAMBaseAddress + 0x00408000; + hw.m_pVPR = hw.m_pLFB + 0x0040c000; + #ifdef __BIG_ENDIAN + if (sfb->fb.var.bits_per_pixel == 32) { +@@ -1035,27 +935,21 @@ + if (sfb->fb.var.bits_per_pixel == 32) + smtc_seqw(0x17, 0x30); + #endif +-#ifdef CONFIG_FB_SM7XX_ACCEL +- smtc_2Dacceleration = 1; +-#endif + break; + case 0x720: + sfb->fb.fix.mmio_start = pFramebufferPhysical; + sfb->fb.fix.mmio_len = 0x00200000; + smem_size = SM722_VIDEOMEMORYSIZE; +- smtc_2DBaseAddress = (hw.m_pDPR = +- ioremap(pFramebufferPhysical, 0x00a00000)); ++ hw.m_pDPR = ioremap(pFramebufferPhysical, 0x00a00000); + hw.m_pLFB = (smtc_VRAMBaseAddress = +- smtc_2DBaseAddress + 0x00200000); ++ hw.m_pDPR + 0x00200000); + hw.m_pMMIO = (smtc_RegBaseAddress = +- smtc_2DBaseAddress + 0x000c0000); +- smtc_2Ddataport = smtc_2DBaseAddress + DE_DATA_PORT_722; +- hw.m_pVPR = smtc_2DBaseAddress + 0x800; ++ hw.m_pDPR + 0x000c0000); ++ hw.m_pVPR = hw.m_pDPR + 0x800; + + smtc_seqw(0x62, 0xff); + smtc_seqw(0x6a, 0x0d); + smtc_seqw(0x6b, 0x02); +- smtc_2Dacceleration = 0; + break; + default: + printk(KERN_INFO +diff -Nur linux-2.6.33/drivers/staging/sm7xx/smtcfb.h linux-lemote/drivers/staging/sm7xx/smtcfb.h +--- linux-2.6.33/drivers/staging/sm7xx/smtcfb.h 2010-02-24 19:52:17.000000000 +0100 ++++ linux-lemote/drivers/staging/sm7xx/smtcfb.h 2010-03-06 16:43:30.000000000 +0100 +@@ -6,7 +6,7 @@ + * Boyod boyod.yang@siliconmotion.com.cn + * + * Copyright (C) 2009 Lemote, Inc. +- * Author: Wu Zhangjin, wuzj@lemote.com ++ * Author: Wu Zhangjin, wuzhangjin@gmail.com + * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file COPYING in the main directory of this archive for +diff -Nur linux-2.6.33/drivers/staging/sm7xx/TODO linux-lemote/drivers/staging/sm7xx/TODO +--- linux-2.6.33/drivers/staging/sm7xx/TODO 2010-02-24 19:52:17.000000000 +0100 ++++ linux-lemote/drivers/staging/sm7xx/TODO 2010-03-06 16:43:30.000000000 +0100 +@@ -1,5 +1,6 @@ + TODO: + - Dual head support ++- 2D acceleration support + - use kernel coding style + - checkpatch.pl clean + - refine the code and remove unused code +diff -Nur linux-2.6.33/drivers/usb/host/ohci-hcd.c linux-lemote/drivers/usb/host/ohci-hcd.c +--- linux-2.6.33/drivers/usb/host/ohci-hcd.c 2010-02-24 19:52:17.000000000 +0100 ++++ linux-lemote/drivers/usb/host/ohci-hcd.c 2010-03-06 16:43:31.000000000 +0100 +@@ -832,9 +832,13 @@ + } + + if (ints & OHCI_INTR_WDH) { +- spin_lock (&ohci->lock); +- dl_done_list (ohci); +- spin_unlock (&ohci->lock); ++ if (ohci->hcca->done_head == 0) { ++ ints &= ~OHCI_INTR_WDH; ++ } else { ++ spin_lock (&ohci->lock); ++ dl_done_list (ohci); ++ spin_unlock (&ohci->lock); ++ } + } + + if (quirk_zfmicro(ohci) && (ints & OHCI_INTR_SF)) { diff --git a/target/lemote/xorg.conf b/target/lemote/xorg.conf new file mode 100644 index 000000000..95b9dffe1 --- /dev/null +++ b/target/lemote/xorg.conf @@ -0,0 +1,61 @@ +Section "ServerLayout" + Identifier "Default Layout" + Screen "Default Screen" + Option "AIGLX" "false" +EndSection + +Section "ServerFlags" + Option "NoTrapSignals" +EndSection + +Section "Module" + Load "vgahw" + Load "fb" + Load "exa" + Load "xaa" + Load "int10" + Load "ddc" + Load "i2c" + Load "vbe" + Disable "glx" + Disable "dri" +EndSection + +Section "Device" + Identifier "card0" + Driver "siliconmotion" + VendorName "Silicon Motion, Inc." + BoardName "SM712 LynxEM+" + BusID "PCI:0:8:0" + Option "AccelMethod" "EXA" + Option "pci_burst" "true" + Option "HWCursor" "false" + Option "SWCursor" "true" + Option "UseBIOS" "false" + Option "PanelSize" "1024x600" +# Option "DualHead" "true" +EndSection + +Section "Device" + Identifier "card1" + Driver "fbdev" + Option "UseFBDev" "true" +EndSection + +Section "Monitor" + Identifier "Generic Monitor" + Option "DPMS" "false" + HorizSync 30-70 + VertRefresh 50-80 +EndSection + +Section "Screen" + Identifier "Default Screen" + Device "card0" + Monitor "Generic Monitor" + DefaultDepth 16 + SubSection "Display" + Modes "1024x600" + # Virtual 1824 600 + EndSubSection +EndSection |