Merge tag 'v3.1.8' of git://git.kernel.org/pub/scm/linux/kernel/git/stable/linux-stable into HEAD
diff --git a/Makefile b/Makefile
index 64a2e76..0d7bd8e 100644
--- a/Makefile
+++ b/Makefile
@@ -245,8 +245,8 @@
HOSTCC = gcc
HOSTCXX = g++
-HOSTCFLAGS = -Wall -Wmissing-prototypes -Wstrict-prototypes -O2 -fomit-frame-pointer
-HOSTCXXFLAGS = -O2
+HOSTCFLAGS = -Wall -Wmissing-prototypes -Wstrict-prototypes -O3 -fomit-frame-pointer
+HOSTCXXFLAGS = -O3
# Decide whether to build built-in, modular, or both.
# Normally, just do built-in.
@@ -561,7 +561,7 @@
ifdef CONFIG_CC_OPTIMIZE_FOR_SIZE
KBUILD_CFLAGS += -Os
else
-KBUILD_CFLAGS += -O2
+KBUILD_CFLAGS += -O3
endif
include $(srctree)/arch/$(SRCARCH)/Makefile
diff --git a/arch/mips/Kconfig b/arch/mips/Kconfig
index b122adc..10e3bdd 100644
--- a/arch/mips/Kconfig
+++ b/arch/mips/Kconfig
@@ -18,12 +18,12 @@
select HAVE_KRETPROBES
select RTC_LIB if !MACH_LOONGSON
select GENERIC_ATOMIC64 if !64BIT
- select HAVE_DMA_ATTRS
- select HAVE_DMA_API_DEBUG
select HAVE_GENERIC_HARDIRQS
select GENERIC_IRQ_PROBE
select GENERIC_IRQ_SHOW
select HAVE_ARCH_JUMP_LABEL
+ select HAVE_DMA_ATTRS
+ select HAVE_DMA_API_DEBUG
select IRQ_FORCED_THREADING
menu "Machine selection"
@@ -250,7 +250,7 @@
config MACH_LOONGSON
bool "Loongson family of machines"
- select SYS_SUPPORTS_ZBOOT
+ select SYS_SUPPORTS_ZBOOT_UART16550
help
This enables the support of Loongson family of machines.
@@ -897,6 +897,60 @@
select CSRC_R4K_LIB
bool
+config MIPS_USER_RDTSC
+ bool "Emulate rdtsc instruction for MIPS"
+ depends on CSRC_R4K && MIPS32_O32
+ default n
+ help
+ This optoin enables the Emulated rdtsc support for MIPS, which allows
+ the user-space applications read the R4k count directly. Currently,
+ this only support the CONFIG_MIPS32_O32 and R4K, but future, we may
+ add support for scall64-{n32,64}.S and scall32-32.S and for the count
+ registers provided by the other MIPS variants.
+
+ This emulation based on the syscall instruction, by default, the
+ syscall is encoded as 0x0000000c, except the 0xc, the other parts can
+ be encoded as specific meaning. when a syscall instruction is issued,
+ through checking the encoding of the instruction, when the encoding
+ is the generic 0x000000c, we do the generic syscall work, if
+ something other is encoded in, we can do relevant things, except for
+ the light-weight things, such as read a register. herein, we read the
+ count register whenever there is something encoded in the syscall
+ instruction. In the future, we may be possible to abstract more
+ light-weight & frequently-used operations and add a
+ sys_call_table-like table to store the entries of some light-weight
+ operations and encode 1,2,3... into the syscall instruction and jump
+ to respective entry for diffrent numbers, as a result, we get
+ fast-syscall and which may speed up the user-space applications and
+ even be possibly improve the determinism.
+
+ *Example*
+
+ #include <stdio.h>
+ #include <stdint.h>
+
+ /*
+ * Currently, our return value is only 32bit, In the long run,
+ * this should be uint64_t, just like clock_gettime(), but it
+ * should has high precision/low overhead than clock_gettime()
+ */
+ uint32_t rdtsc(void)
+ {
+ /*
+ * Linux will store the value of the count register into
+ * the v0 register, which is just the return value of this
+ * function, so, please ignore the compiling warning.
+ */
+ __asm__ __volatile__ (
+ "syscall 1\n"
+ :::"$2");
+ }
+
+ int main(int argc, char *argv[])
+ {
+ return printf("cycles: %u\n", rdtsc());
+ }
+
config CSRC_SB1250
bool
@@ -1187,8 +1241,6 @@
bool "Loongson 2F"
depends on SYS_HAS_CPU_LOONGSON2F
select CPU_LOONGSON2
- select GENERIC_GPIO
- select ARCH_REQUIRE_GPIOLIB
help
The Loongson 2F processor implements the MIPS III instruction set
with many extensions.
@@ -1523,7 +1575,8 @@
bool
select CPU_SUPPORTS_32BIT_KERNEL
select CPU_SUPPORTS_64BIT_KERNEL
- select CPU_SUPPORTS_HIGHMEM
+ select CPU_SUPPORTS_HIGHMEM if ! EMBEDDED
+ select ARCH_WANT_OPTIONAL_GPIOLIB
config SYS_HAS_CPU_LOONGSON2E
bool
@@ -2060,7 +2113,7 @@
config ARCH_FLATMEM_ENABLE
def_bool y
- depends on !NUMA && !CPU_LOONGSON2
+ depends on !NUMA && !(CPU_LOONGSON2 && HIBERNATION)
config ARCH_DISCONTIGMEM_ENABLE
bool
diff --git a/arch/mips/Kconfig.debug b/arch/mips/Kconfig.debug
index 83ed00a..bdb259d 100644
--- a/arch/mips/Kconfig.debug
+++ b/arch/mips/Kconfig.debug
@@ -7,9 +7,9 @@
source "lib/Kconfig.debug"
config EARLY_PRINTK
- bool "Early printk" if EXPERT
+ bool "Early printk"
depends on SYS_HAS_EARLY_PRINTK
- default y
+ default n
help
This option enables special console drivers which allow the kernel
to print messages very early in the bootup process.
diff --git a/arch/mips/Makefile b/arch/mips/Makefile
index 53e3514..f1bdcc9 100644
--- a/arch/mips/Makefile
+++ b/arch/mips/Makefile
@@ -256,18 +256,19 @@
# Other need ECOFF, so we build a 32-bit ELF binary for them which we then
# convert to ECOFF using elf2ecoff.
#
+quiet_cmd_32 = OBJCOPY $@
+ cmd_32 = $(OBJCOPY) -O $(32bit-bfd) $(OBJCOPYFLAGS) $< $@
vmlinux.32: vmlinux
- $(OBJCOPY) -O $(32bit-bfd) $(OBJCOPYFLAGS) $< $@
-
-
-#obj-$(CONFIG_KPROBES) += kprobes.o
+ $(call cmd,32)
#
# The 64-bit ELF tools are pretty broken so at this time we generate 64-bit
# ELF files from 32-bit files by conversion.
#
+quiet_cmd_64 = OBJCOPY $@
+ cmd_64 = $(OBJCOPY) -O $(64bit-bfd) $(OBJCOPYFLAGS) $< $@
vmlinux.64: vmlinux
- $(OBJCOPY) -O $(64bit-bfd) $(OBJCOPYFLAGS) $< $@
+ $(call cmd,64)
all: $(all-y)
diff --git a/arch/mips/bcm63xx/cpu.c b/arch/mips/bcm63xx/cpu.c
index 7c7e4d4..5e5caae 100644
--- a/arch/mips/bcm63xx/cpu.c
+++ b/arch/mips/bcm63xx/cpu.c
@@ -297,7 +297,7 @@
/* soc registers location depends on cpu type */
expected_cpu_id = 0;
- switch (c->cputype) {
+ switch (current_cpu_type()) {
case CPU_BMIPS3300:
if ((read_c0_prid() & 0xff00) == PRID_IMP_BMIPS3300_ALT) {
expected_cpu_id = BCM6348_CPU_ID;
diff --git a/arch/mips/boot/compressed/Makefile b/arch/mips/boot/compressed/Makefile
index 5042d51..c653ebd 100644
--- a/arch/mips/boot/compressed/Makefile
+++ b/arch/mips/boot/compressed/Makefile
@@ -28,9 +28,10 @@
targets := head.o decompress.o dbg.o uart-16550.o uart-alchemy.o
# decompressor objects (linked with vmlinuz)
-vmlinuzobjs-y := $(obj)/head.o $(obj)/decompress.o $(obj)/dbg.o
+vmlinuzobjs-y := $(obj)/head.o $(obj)/decompress.o
ifdef CONFIG_DEBUG_ZBOOT
+vmlinuzobjs-y += $(obj)/dbg.o
vmlinuzobjs-$(CONFIG_SYS_SUPPORTS_ZBOOT_UART16550) += $(obj)/uart-16550.o
vmlinuzobjs-$(CONFIG_MIPS_ALCHEMY) += $(obj)/uart-alchemy.o
endif
@@ -67,9 +68,18 @@
cmd_zld = $(LD) $(LDFLAGS) -Ttext $(VMLINUZ_LOAD_ADDRESS) -T $< $(vmlinuzobjs-y) -o $@
quiet_cmd_strip = STRIP $@
cmd_strip = $(STRIP) -s $@
+ifdef CONFIG_EMBEDDED
+quiet_cmd_sstrip = SSTRIP $@
+ cmd_sstrip = $(srctree)/scripts/sstrip.sh $@
+endif
vmlinuz: $(src)/ld.script $(vmlinuzobjs-y) $(obj)/calc_vmlinuz_load_addr
$(call cmd,zld)
$(call cmd,strip)
+ $(call cmd,sstrip)
+
+vmlinuz.unsstrip: $(src)/ld.script $(vmlinuzobjs-y) $(obj)/calc_vmlinuz_load_addr
+ $(call cmd,zld)
+ $(call cmd,strip)
#
# Some DECstations need all possible sections of an ECOFF executable
@@ -82,14 +92,14 @@
hostprogs-y += ../elf2ecoff
ifdef CONFIG_32BIT
- VMLINUZ = vmlinuz
+ VMLINUZ = vmlinuz.unsstrip
else
VMLINUZ = vmlinuz.32
endif
quiet_cmd_32 = OBJCOPY $@
cmd_32 = $(OBJCOPY) -O $(32bit-bfd) $(OBJCOPYFLAGS) $< $@
-vmlinuz.32: vmlinuz
+vmlinuz.32: vmlinuz.unsstrip
$(call cmd,32)
quiet_cmd_ecoff = ECOFF $@
@@ -98,11 +108,11 @@
$(call cmd,ecoff)
OBJCOPYFLAGS_vmlinuz.bin := $(OBJCOPYFLAGS) -O binary
-vmlinuz.bin: vmlinuz
+vmlinuz.bin: vmlinuz.unsstrip
$(call cmd,objcopy)
OBJCOPYFLAGS_vmlinuz.srec := $(OBJCOPYFLAGS) -S -O srec
-vmlinuz.srec: vmlinuz
+vmlinuz.srec: vmlinuz.unsstrip
$(call cmd,objcopy)
-clean-files := $(objtree)/vmlinuz $(objtree)/vmlinuz.{32,ecoff,bin,srec}
+clean-files := $(objtree)/vmlinuz $(objtree)/vmlinuz.{32,ecoff,bin,srec,unsstrip}
diff --git a/arch/mips/boot/compressed/decompress.c b/arch/mips/boot/compressed/decompress.c
index 5cad0fa..2f761a5 100644
--- a/arch/mips/boot/compressed/decompress.c
+++ b/arch/mips/boot/compressed/decompress.c
@@ -27,8 +27,13 @@
extern unsigned char __image_begin, __image_end;
/* debug interfaces */
+#ifdef CONFIG_DEBUG_ZBOOT
extern void puts(const char *s);
extern void puthex(unsigned long long val);
+#else
+#define puts(s)
+#define puthex(val)
+#endif
void error(char *x)
{
diff --git a/arch/mips/boot/compressed/ld.script b/arch/mips/boot/compressed/ld.script
index 8e6b07c..99ca111 100644
--- a/arch/mips/boot/compressed/ld.script
+++ b/arch/mips/boot/compressed/ld.script
@@ -46,5 +46,6 @@
*(.reginfo)
*(.comment)
*(.note)
+ *(.gnu.attributes)
}
}
diff --git a/arch/mips/configs/fuloong2e_defconfig b/arch/mips/configs/fuloong2e_defconfig
index e5b73de..1e02d0b 100644
--- a/arch/mips/configs/fuloong2e_defconfig
+++ b/arch/mips/configs/fuloong2e_defconfig
@@ -12,7 +12,6 @@
CONFIG_IKCONFIG=y
CONFIG_IKCONFIG_PROC=y
CONFIG_LOG_BUF_SHIFT=14
-CONFIG_SYSFS_DEPRECATED_V2=y
CONFIG_NAMESPACES=y
CONFIG_USER_NS=y
CONFIG_PID_NS=y
@@ -222,7 +221,8 @@
CONFIG_REISERFS_FS=m
CONFIG_AUTOFS_FS=y
CONFIG_AUTOFS4_FS=y
-CONFIG_FUSE_FS=y
+CONFIG_FUSE_FS=m
+CONFIG_CUSE=m
CONFIG_ISO9660_FS=m
CONFIG_JOLIET=y
CONFIG_ZISOFS=y
@@ -260,9 +260,9 @@
CONFIG_NLS_ISO8859_1=y
CONFIG_NLS_UTF8=y
# CONFIG_ENABLE_MUST_CHECK is not set
-CONFIG_DEBUG_FS=y
# CONFIG_RCU_CPU_STALL_DETECTOR is not set
CONFIG_SYSCTL_SYSCALL_CHECK=y
+# CONFIG_EARLY_PRINTK is not set
CONFIG_CRYPTO_FIPS=y
CONFIG_CRYPTO_AUTHENC=m
CONFIG_CRYPTO_CCM=m
diff --git a/arch/mips/configs/gdium_minimal_defconfig b/arch/mips/configs/gdium_minimal_defconfig
new file mode 100644
index 0000000..595b414
--- /dev/null
+++ b/arch/mips/configs/gdium_minimal_defconfig
@@ -0,0 +1,125 @@
+CONFIG_MACH_LOONGSON=y
+CONFIG_DEXXON_GDIUM=y
+CONFIG_64BIT=y
+CONFIG_NO_HZ=y
+CONFIG_HIGH_RES_TIMERS=y
+CONFIG_PREEMPT=y
+CONFIG_EXPERIMENTAL=y
+# CONFIG_LOCALVERSION_AUTO is not set
+CONFIG_KERNEL_LZMA=y
+CONFIG_SYSVIPC=y
+CONFIG_POSIX_MQUEUE=y
+CONFIG_BSD_PROCESS_ACCT=y
+CONFIG_BSD_PROCESS_ACCT_V3=y
+CONFIG_IKCONFIG=y
+CONFIG_IKCONFIG_PROC=y
+CONFIG_LOG_BUF_SHIFT=15
+CONFIG_BLK_DEV_INITRD=y
+# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
+CONFIG_EMBEDDED=y
+# CONFIG_BLK_DEV_BSG is not set
+# CONFIG_IOSCHED_DEADLINE is not set
+# CONFIG_IOSCHED_CFQ is not set
+CONFIG_PCI=y
+CONFIG_MIPS32_COMPAT=y
+CONFIG_MIPS32_O32=y
+CONFIG_MIPS32_N32=y
+CONFIG_NET=y
+CONFIG_PACKET=y
+CONFIG_UNIX=y
+CONFIG_INET=y
+# CONFIG_INET_XFRM_MODE_TRANSPORT is not set
+# CONFIG_INET_XFRM_MODE_TUNNEL is not set
+# CONFIG_INET_XFRM_MODE_BEET is not set
+# CONFIG_INET_LRO is not set
+# CONFIG_INET_DIAG is not set
+# CONFIG_IPV6 is not set
+# CONFIG_WIRELESS is not set
+CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
+CONFIG_DEVTMPFS=y
+CONFIG_DEVTMPFS_MOUNT=y
+CONFIG_SCSI=y
+CONFIG_BLK_DEV_SD=y
+CONFIG_NETDEVICES=y
+CONFIG_NET_ETHERNET=y
+CONFIG_NET_PCI=y
+CONFIG_8139TOO=y
+CONFIG_R8169=y
+# CONFIG_NETDEV_10000 is not set
+# CONFIG_WLAN is not set
+# CONFIG_INPUT_MOUSEDEV_PSAUX is not set
+CONFIG_INPUT_EVDEV=y
+# CONFIG_MOUSE_PS2_ALPS is not set
+# CONFIG_MOUSE_PS2_LOGIPS2PP is not set
+# CONFIG_MOUSE_PS2_TRACKPOINT is not set
+# CONFIG_SERIO_SERPORT is not set
+# CONFIG_DEVKMEM is not set
+CONFIG_SERIAL_8250=y
+CONFIG_SERIAL_8250_CONSOLE=y
+CONFIG_LEGACY_PTY_COUNT=16
+# CONFIG_HW_RANDOM is not set
+CONFIG_I2C=y
+CONFIG_I2C_CHARDEV=y
+CONFIG_I2C_GPIO=y
+CONFIG_SENSORS_LM75=y
+CONFIG_MFD_SM501=y
+CONFIG_MFD_SM501_GPIO=y
+CONFIG_FB=y
+CONFIG_FB_SIS=y
+CONFIG_FB_SIS_300=y
+CONFIG_FB_SIS_315=y
+CONFIG_FB_SM501=y
+# CONFIG_VGA_CONSOLE is not set
+CONFIG_FRAMEBUFFER_CONSOLE=y
+CONFIG_HIDRAW=y
+CONFIG_USB_HIDDEV=y
+CONFIG_HID_DRAGONRISE=y
+CONFIG_DRAGONRISE_FF=y
+CONFIG_HID_GYRATION=y
+CONFIG_HID_TWINHAN=y
+CONFIG_HID_NTRIG=y
+CONFIG_HID_PANTHERLORD=y
+CONFIG_PANTHERLORD_FF=y
+CONFIG_HID_PETALYNX=y
+CONFIG_HID_SAMSUNG=y
+CONFIG_HID_SONY=y
+CONFIG_HID_SUNPLUS=y
+CONFIG_HID_GREENASIA=y
+CONFIG_GREENASIA_FF=y
+CONFIG_HID_SMARTJOYPLUS=y
+CONFIG_SMARTJOYPLUS_FF=y
+CONFIG_HID_TOPSEED=y
+CONFIG_HID_THRUSTMASTER=y
+CONFIG_THRUSTMASTER_FF=y
+CONFIG_HID_ZEROPLUS=y
+CONFIG_ZEROPLUS_FF=y
+CONFIG_USB=y
+# CONFIG_USB_DEVICE_CLASS is not set
+CONFIG_USB_DYNAMIC_MINORS=y
+CONFIG_USB_MON=y
+CONFIG_USB_EHCI_HCD=y
+CONFIG_USB_EHCI_ROOT_HUB_TT=y
+# CONFIG_USB_EHCI_TT_NEWSCHED is not set
+CONFIG_USB_OHCI_HCD=y
+CONFIG_USB_STORAGE=y
+CONFIG_USB_LIBUSUAL=y
+CONFIG_RTC_CLASS=y
+CONFIG_RTC_DRV_M41T80=y
+CONFIG_STAGING=y
+# CONFIG_STAGING_EXCLUDE_BUILD is not set
+CONFIG_FB_SM7XX=y
+# CONFIG_MIPS_PLATFORM_DEVICES is not set
+CONFIG_EXT2_FS=y
+CONFIG_EXT2_FS_XATTR=y
+CONFIG_EXT3_FS=y
+# CONFIG_EXT3_DEFAULTS_TO_ORDERED is not set
+CONFIG_EXT4_FS=y
+CONFIG_TMPFS=y
+# CONFIG_MISC_FILESYSTEMS is not set
+# CONFIG_NETWORK_FILESYSTEMS is not set
+CONFIG_NLS_DEFAULT="utf8"
+CONFIG_NLS_ASCII=y
+CONFIG_NLS_UTF8=y
+CONFIG_FRAME_WARN=1024
+CONFIG_STRIP_ASM_SYMS=y
+# CONFIG_RCU_CPU_STALL_DETECTOR is not set
diff --git a/arch/mips/configs/gdium_small_defconfig b/arch/mips/configs/gdium_small_defconfig
new file mode 100644
index 0000000..641daf5
--- /dev/null
+++ b/arch/mips/configs/gdium_small_defconfig
@@ -0,0 +1,150 @@
+CONFIG_MACH_LOONGSON=y
+CONFIG_DEXXON_GDIUM=y
+CONFIG_64BIT=y
+CONFIG_NO_HZ=y
+CONFIG_HIGH_RES_TIMERS=y
+CONFIG_PREEMPT=y
+CONFIG_EXPERIMENTAL=y
+# CONFIG_LOCALVERSION_AUTO is not set
+CONFIG_KERNEL_LZMA=y
+CONFIG_SYSVIPC=y
+CONFIG_POSIX_MQUEUE=y
+CONFIG_BSD_PROCESS_ACCT=y
+CONFIG_BSD_PROCESS_ACCT_V3=y
+CONFIG_IKCONFIG=y
+CONFIG_IKCONFIG_PROC=y
+CONFIG_LOG_BUF_SHIFT=15
+CONFIG_NAMESPACES=y
+# CONFIG_UTS_NS is not set
+# CONFIG_IPC_NS is not set
+# CONFIG_USER_NS is not set
+# CONFIG_PID_NS is not set
+# CONFIG_NET_NS is not set
+CONFIG_BLK_DEV_INITRD=y
+# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
+CONFIG_EMBEDDED=y
+CONFIG_MODULES=y
+CONFIG_MODULE_UNLOAD=y
+# CONFIG_BLK_DEV_BSG is not set
+# CONFIG_IOSCHED_DEADLINE is not set
+# CONFIG_IOSCHED_CFQ is not set
+CONFIG_PCI=y
+# CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS is not set
+CONFIG_MIPS32_COMPAT=y
+CONFIG_MIPS32_O32=y
+CONFIG_MIPS32_N32=y
+CONFIG_PM=y
+CONFIG_HIBERNATION=y
+CONFIG_PM_STD_PARTITION="/dev/sda4"
+CONFIG_R4K_TIMER_FOR_CPUFREQ=y
+CONFIG_CPU_FREQ=y
+CONFIG_CPU_FREQ_STAT_DETAILS=y
+CONFIG_CPU_FREQ_DEFAULT_GOV_CONSERVATIVE=y
+CONFIG_CPU_FREQ_GOV_POWERSAVE=y
+CONFIG_CPU_FREQ_GOV_USERSPACE=y
+CONFIG_CPU_FREQ_GOV_ONDEMAND=y
+CONFIG_LOONGSON2_CPUFREQ=m
+CONFIG_NET=y
+CONFIG_PACKET=y
+CONFIG_UNIX=y
+CONFIG_INET=y
+# CONFIG_INET_XFRM_MODE_TRANSPORT is not set
+# CONFIG_INET_XFRM_MODE_TUNNEL is not set
+# CONFIG_INET_XFRM_MODE_BEET is not set
+# CONFIG_INET_LRO is not set
+# CONFIG_INET_DIAG is not set
+# CONFIG_IPV6 is not set
+CONFIG_CFG80211=y
+# CONFIG_CFG80211_DEFAULT_PS is not set
+# CONFIG_CFG80211_WEXT is not set
+CONFIG_LIB80211=y
+CONFIG_MAC80211=y
+CONFIG_RFKILL=y
+CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
+CONFIG_DEVTMPFS=y
+CONFIG_DEVTMPFS_MOUNT=y
+CONFIG_BLK_DEV_LOOP=y
+CONFIG_BLK_DEV_RAM=y
+CONFIG_BLK_DEV_RAM_SIZE=8192
+CONFIG_MISC_DEVICES=y
+# CONFIG_SCSI_PROC_FS is not set
+CONFIG_BLK_DEV_SD=y
+# CONFIG_SCSI_LOWLEVEL is not set
+CONFIG_ATA=y
+# CONFIG_SATA_PMP is not set
+CONFIG_PATA_AMD=y
+CONFIG_NETDEVICES=y
+CONFIG_NET_ETHERNET=y
+CONFIG_NET_PCI=y
+CONFIG_8139TOO=y
+CONFIG_R8169=y
+# CONFIG_NETDEV_10000 is not set
+CONFIG_RT2X00=m
+CONFIG_RT61PCI=m
+CONFIG_INPUT_FF_MEMLESS=y
+CONFIG_INPUT_EVDEV=y
+CONFIG_MOUSE_PS2=m
+# CONFIG_MOUSE_PS2_ALPS is not set
+# CONFIG_MOUSE_PS2_LOGIPS2PP is not set
+# CONFIG_MOUSE_PS2_TRACKPOINT is not set
+# CONFIG_SERIO_SERPORT is not set
+# CONFIG_DEVKMEM is not set
+CONFIG_SERIAL_8250=y
+CONFIG_SERIAL_8250_CONSOLE=y
+CONFIG_LEGACY_PTY_COUNT=16
+# CONFIG_HW_RANDOM is not set
+CONFIG_I2C=y
+CONFIG_I2C_CHARDEV=y
+CONFIG_I2C_GPIO=y
+CONFIG_HWMON=m
+CONFIG_SENSORS_LM75=m
+CONFIG_MFD_SM501=y
+CONFIG_MFD_SM501_GPIO=y
+CONFIG_FB=y
+CONFIG_FB_SIS=y
+CONFIG_FB_SIS_300=y
+CONFIG_FB_SIS_315=y
+CONFIG_FB_SM501=y
+CONFIG_BACKLIGHT_LCD_SUPPORT=y
+# CONFIG_BACKLIGHT_GENERIC is not set
+CONFIG_BACKLIGHT_PWM=m
+# CONFIG_VGA_CONSOLE is not set
+CONFIG_FRAMEBUFFER_CONSOLE=y
+CONFIG_SOUND=y
+CONFIG_SND=y
+CONFIG_SND_CS5535AUDIO=m
+CONFIG_HIDRAW=y
+CONFIG_USB_HIDDEV=y
+CONFIG_HID_GDIUM=y
+CONFIG_USB=y
+# CONFIG_USB_DEVICE_CLASS is not set
+CONFIG_USB_DYNAMIC_MINORS=y
+CONFIG_USB_MON=y
+CONFIG_USB_EHCI_HCD=y
+CONFIG_USB_EHCI_ROOT_HUB_TT=y
+# CONFIG_USB_EHCI_TT_NEWSCHED is not set
+CONFIG_USB_OHCI_HCD=y
+CONFIG_USB_STORAGE=y
+CONFIG_USB_LIBUSUAL=y
+CONFIG_RTC_CLASS=y
+CONFIG_RTC_DRV_M41T80=y
+CONFIG_RTC_DRV_M41T80_WDT=y
+CONFIG_STAGING=y
+# CONFIG_STAGING_EXCLUDE_BUILD is not set
+CONFIG_FB_SM7XX=y
+CONFIG_EXT2_FS=y
+CONFIG_EXT2_FS_XATTR=y
+CONFIG_EXT3_FS=y
+# CONFIG_EXT3_DEFAULTS_TO_ORDERED is not set
+CONFIG_EXT4_FS=y
+CONFIG_FANOTIFY=y
+CONFIG_TMPFS=y
+# CONFIG_MISC_FILESYSTEMS is not set
+# CONFIG_NETWORK_FILESYSTEMS is not set
+CONFIG_NLS_DEFAULT="utf8"
+CONFIG_NLS_ASCII=y
+CONFIG_NLS_UTF8=y
+CONFIG_FRAME_WARN=1024
+CONFIG_STRIP_ASM_SYMS=y
+# CONFIG_RCU_CPU_STALL_DETECTOR is not set
+# CONFIG_EARLY_PRINTK is not set
diff --git a/arch/mips/configs/lemote2f_defconfig b/arch/mips/configs/lemote2f_defconfig
index b6acd2f..abc42e0 100644
--- a/arch/mips/configs/lemote2f_defconfig
+++ b/arch/mips/configs/lemote2f_defconfig
@@ -1,27 +1,27 @@
CONFIG_MACH_LOONGSON=y
CONFIG_LEMOTE_MACH2F=y
-CONFIG_CS5536_MFGPT=y
CONFIG_64BIT=y
+CONFIG_KSM=y
CONFIG_NO_HZ=y
CONFIG_HIGH_RES_TIMERS=y
CONFIG_PREEMPT=y
-CONFIG_KEXEC=y
-# CONFIG_SECCOMP is not set
CONFIG_EXPERIMENTAL=y
# CONFIG_LOCALVERSION_AUTO is not set
+CONFIG_KERNEL_LZMA=y
CONFIG_SYSVIPC=y
CONFIG_BSD_PROCESS_ACCT=y
CONFIG_BSD_PROCESS_ACCT_V3=y
+CONFIG_TASKSTATS=y
+CONFIG_TASK_DELAY_ACCT=y
+CONFIG_TASK_XACCT=y
+CONFIG_TASK_IO_ACCOUNTING=y
CONFIG_AUDIT=y
CONFIG_IKCONFIG=y
CONFIG_IKCONFIG_PROC=y
CONFIG_LOG_BUF_SHIFT=15
-CONFIG_SYSFS_DEPRECATED_V2=y
+CONFIG_SCHED_AUTOGROUP=y
CONFIG_BLK_DEV_INITRD=y
-CONFIG_RD_BZIP2=y
-CONFIG_RD_LZMA=y
# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
-CONFIG_EXPERT=y
CONFIG_PROFILING=y
CONFIG_OPROFILE=m
CONFIG_MODULES=y
@@ -34,20 +34,18 @@
CONFIG_MIPS32_COMPAT=y
CONFIG_MIPS32_O32=y
CONFIG_MIPS32_N32=y
-CONFIG_PM=y
CONFIG_HIBERNATION=y
-CONFIG_PM_STD_PARTITION="/dev/hda3"
+CONFIG_PM_STD_PARTITION="/dev/sda3"
CONFIG_PM_RUNTIME=y
+CONFIG_R4K_TIMER_FOR_CPUFREQ=y
CONFIG_CPU_FREQ=y
CONFIG_CPU_FREQ_DEBUG=y
-CONFIG_CPU_FREQ_STAT=m
CONFIG_CPU_FREQ_STAT_DETAILS=y
-CONFIG_CPU_FREQ_DEFAULT_GOV_ONDEMAND=y
-CONFIG_CPU_FREQ_GOV_POWERSAVE=m
-CONFIG_CPU_FREQ_GOV_USERSPACE=m
-CONFIG_CPU_FREQ_GOV_CONSERVATIVE=m
+CONFIG_CPU_FREQ_DEFAULT_GOV_CONSERVATIVE=y
+CONFIG_CPU_FREQ_GOV_POWERSAVE=y
+CONFIG_CPU_FREQ_GOV_USERSPACE=y
+CONFIG_CPU_FREQ_GOV_ONDEMAND=y
CONFIG_LOONGSON2_CPUFREQ=m
-CONFIG_NET=y
CONFIG_PACKET=y
CONFIG_UNIX=y
CONFIG_XFRM_USER=m
@@ -59,7 +57,6 @@
CONFIG_IP_ROUTE_MULTIPATH=y
CONFIG_IP_ROUTE_VERBOSE=y
CONFIG_NET_IPIP=m
-CONFIG_NET_IPGRE=m
CONFIG_IP_MROUTE=y
CONFIG_IP_PIMSM_V1=y
CONFIG_IP_PIMSM_V2=y
@@ -79,12 +76,249 @@
CONFIG_IPV6_SUBTREES=y
CONFIG_NETWORK_SECMARK=y
CONFIG_NETFILTER=y
+CONFIG_NF_CONNTRACK=m
+CONFIG_NF_CT_PROTO_UDPLITE=m
+CONFIG_NF_CONNTRACK_AMANDA=m
+CONFIG_NF_CONNTRACK_FTP=m
+CONFIG_NF_CONNTRACK_H323=m
+CONFIG_NF_CONNTRACK_IRC=m
+CONFIG_NF_CONNTRACK_NETBIOS_NS=m
+CONFIG_NF_CONNTRACK_PPTP=m
+CONFIG_NF_CONNTRACK_SANE=m
+CONFIG_NF_CONNTRACK_SIP=m
+CONFIG_NF_CONNTRACK_TFTP=m
+CONFIG_NF_CT_NETLINK=m
+CONFIG_NETFILTER_TPROXY=m
+CONFIG_NETFILTER_XT_TARGET_CHECKSUM=m
+CONFIG_NETFILTER_XT_TARGET_CLASSIFY=m
+CONFIG_NETFILTER_XT_TARGET_CONNMARK=m
+CONFIG_NETFILTER_XT_TARGET_CT=m
+CONFIG_NETFILTER_XT_TARGET_DSCP=m
+CONFIG_NETFILTER_XT_TARGET_IDLETIMER=m
+CONFIG_NETFILTER_XT_TARGET_MARK=m
+CONFIG_NETFILTER_XT_TARGET_NFLOG=m
+CONFIG_NETFILTER_XT_TARGET_NFQUEUE=m
+CONFIG_NETFILTER_XT_TARGET_NOTRACK=m
+CONFIG_NETFILTER_XT_TARGET_TEE=m
+CONFIG_NETFILTER_XT_TARGET_TPROXY=m
+CONFIG_NETFILTER_XT_TARGET_TRACE=m
+CONFIG_NETFILTER_XT_TARGET_SECMARK=m
+CONFIG_NETFILTER_XT_TARGET_TCPMSS=m
+CONFIG_NETFILTER_XT_TARGET_TCPOPTSTRIP=m
+CONFIG_NETFILTER_XT_MATCH_CLUSTER=m
+CONFIG_NETFILTER_XT_MATCH_COMMENT=m
+CONFIG_NETFILTER_XT_MATCH_CONNBYTES=m
+CONFIG_NETFILTER_XT_MATCH_CONNLIMIT=m
+CONFIG_NETFILTER_XT_MATCH_CONNMARK=m
+CONFIG_NETFILTER_XT_MATCH_CONNTRACK=m
+CONFIG_NETFILTER_XT_MATCH_CPU=m
+CONFIG_NETFILTER_XT_MATCH_DSCP=m
+CONFIG_NETFILTER_XT_MATCH_ESP=m
+CONFIG_NETFILTER_XT_MATCH_HASHLIMIT=m
+CONFIG_NETFILTER_XT_MATCH_HELPER=m
+CONFIG_NETFILTER_XT_MATCH_IPRANGE=m
+CONFIG_NETFILTER_XT_MATCH_IPVS=m
+CONFIG_NETFILTER_XT_MATCH_LENGTH=m
+CONFIG_NETFILTER_XT_MATCH_LIMIT=m
+CONFIG_NETFILTER_XT_MATCH_MAC=m
+CONFIG_NETFILTER_XT_MATCH_MARK=m
+CONFIG_NETFILTER_XT_MATCH_MULTIPORT=m
+CONFIG_NETFILTER_XT_MATCH_OSF=m
+CONFIG_NETFILTER_XT_MATCH_OWNER=m
+CONFIG_NETFILTER_XT_MATCH_POLICY=m
+CONFIG_NETFILTER_XT_MATCH_PHYSDEV=m
+CONFIG_NETFILTER_XT_MATCH_PKTTYPE=m
+CONFIG_NETFILTER_XT_MATCH_QUOTA=m
+CONFIG_NETFILTER_XT_MATCH_RATEEST=m
+CONFIG_NETFILTER_XT_MATCH_REALM=m
+CONFIG_NETFILTER_XT_MATCH_RECENT=m
+CONFIG_NETFILTER_XT_MATCH_SOCKET=m
+CONFIG_NETFILTER_XT_MATCH_STATE=m
+CONFIG_NETFILTER_XT_MATCH_STATISTIC=m
+CONFIG_NETFILTER_XT_MATCH_STRING=m
+CONFIG_NETFILTER_XT_MATCH_TCPMSS=m
+CONFIG_NETFILTER_XT_MATCH_TIME=m
+CONFIG_NETFILTER_XT_MATCH_U32=m
+CONFIG_IP_VS=m
+CONFIG_IP_VS_IPV6=y
+CONFIG_IP_VS_PROTO_TCP=y
+CONFIG_IP_VS_PROTO_UDP=y
+CONFIG_IP_VS_PROTO_ESP=y
+CONFIG_IP_VS_PROTO_AH=y
+CONFIG_IP_VS_PROTO_SCTP=y
+CONFIG_IP_VS_RR=m
+CONFIG_IP_VS_WRR=m
+CONFIG_IP_VS_LC=m
+CONFIG_IP_VS_WLC=m
+CONFIG_IP_VS_LBLC=m
+CONFIG_IP_VS_LBLCR=m
+CONFIG_IP_VS_DH=m
+CONFIG_IP_VS_SH=m
+CONFIG_IP_VS_SED=m
+CONFIG_IP_VS_NQ=m
+CONFIG_IP_VS_FTP=m
+CONFIG_NF_CONNTRACK_IPV4=m
+CONFIG_IP_NF_QUEUE=m
+CONFIG_IP_NF_IPTABLES=m
+CONFIG_IP_NF_MATCH_AH=m
+CONFIG_IP_NF_MATCH_ECN=m
+CONFIG_IP_NF_MATCH_TTL=m
+CONFIG_IP_NF_FILTER=m
+CONFIG_IP_NF_TARGET_REJECT=m
+CONFIG_IP_NF_TARGET_LOG=m
+CONFIG_IP_NF_TARGET_ULOG=m
+CONFIG_NF_NAT=m
+CONFIG_IP_NF_TARGET_MASQUERADE=m
+CONFIG_IP_NF_TARGET_NETMAP=m
+CONFIG_IP_NF_TARGET_REDIRECT=m
+CONFIG_IP_NF_MANGLE=m
+CONFIG_IP_NF_TARGET_CLUSTERIP=m
+CONFIG_IP_NF_TARGET_ECN=m
+CONFIG_IP_NF_TARGET_TTL=m
+CONFIG_IP_NF_RAW=m
+CONFIG_IP_NF_ARPTABLES=m
+CONFIG_IP_NF_ARPFILTER=m
+CONFIG_IP_NF_ARP_MANGLE=m
+CONFIG_NF_CONNTRACK_IPV6=m
+CONFIG_IP6_NF_QUEUE=m
+CONFIG_IP6_NF_IPTABLES=m
+CONFIG_IP6_NF_MATCH_AH=m
+CONFIG_IP6_NF_MATCH_EUI64=m
+CONFIG_IP6_NF_MATCH_FRAG=m
+CONFIG_IP6_NF_MATCH_OPTS=m
+CONFIG_IP6_NF_MATCH_HL=m
+CONFIG_IP6_NF_MATCH_IPV6HEADER=m
+CONFIG_IP6_NF_MATCH_MH=m
+CONFIG_IP6_NF_MATCH_RT=m
+CONFIG_IP6_NF_TARGET_HL=m
+CONFIG_IP6_NF_TARGET_LOG=m
+CONFIG_IP6_NF_FILTER=m
+CONFIG_IP6_NF_TARGET_REJECT=m
+CONFIG_IP6_NF_MANGLE=m
+CONFIG_IP6_NF_RAW=m
+CONFIG_BRIDGE_NF_EBTABLES=m
+CONFIG_BRIDGE_EBT_BROUTE=m
+CONFIG_BRIDGE_EBT_T_FILTER=m
+CONFIG_BRIDGE_EBT_T_NAT=m
+CONFIG_BRIDGE_EBT_802_3=m
+CONFIG_BRIDGE_EBT_AMONG=m
+CONFIG_BRIDGE_EBT_ARP=m
+CONFIG_BRIDGE_EBT_IP=m
+CONFIG_BRIDGE_EBT_IP6=m
+CONFIG_BRIDGE_EBT_LIMIT=m
+CONFIG_BRIDGE_EBT_MARK=m
+CONFIG_BRIDGE_EBT_PKTTYPE=m
+CONFIG_BRIDGE_EBT_STP=m
+CONFIG_BRIDGE_EBT_VLAN=m
+CONFIG_BRIDGE_EBT_ARPREPLY=m
+CONFIG_BRIDGE_EBT_DNAT=m
+CONFIG_BRIDGE_EBT_MARK_T=m
+CONFIG_BRIDGE_EBT_REDIRECT=m
+CONFIG_BRIDGE_EBT_SNAT=m
+CONFIG_BRIDGE_EBT_LOG=m
+CONFIG_BRIDGE_EBT_ULOG=m
+CONFIG_BRIDGE_EBT_NFLOG=m
+CONFIG_IP_DCCP=m
+CONFIG_IP_SCTP=m
+CONFIG_RDS=m
+CONFIG_RDS_TCP=m
+CONFIG_TIPC=m
+CONFIG_TIPC_ADVANCED=y
+CONFIG_ATM=m
+CONFIG_ATM_CLIP=m
+CONFIG_ATM_CLIP_NO_ICMP=y
+CONFIG_ATM_LANE=m
+CONFIG_ATM_MPOA=m
+CONFIG_ATM_BR2684=m
+CONFIG_ATM_BR2684_IPFILTER=y
+CONFIG_L2TP=m
+CONFIG_L2TP_DEBUGFS=m
+CONFIG_L2TP_V3=y
+CONFIG_L2TP_IP=m
+CONFIG_L2TP_ETH=m
CONFIG_BRIDGE=m
CONFIG_VLAN_8021Q=m
-CONFIG_IPX=m
+CONFIG_ATALK=m
CONFIG_NET_SCHED=y
+CONFIG_NET_SCH_CBQ=m
+CONFIG_NET_SCH_HTB=m
+CONFIG_NET_SCH_HFSC=m
+CONFIG_NET_SCH_ATM=m
+CONFIG_NET_SCH_PRIO=m
+CONFIG_NET_SCH_MULTIQ=m
+CONFIG_NET_SCH_RED=m
+CONFIG_NET_SCH_SFQ=m
+CONFIG_NET_SCH_TEQL=m
+CONFIG_NET_SCH_TBF=m
+CONFIG_NET_SCH_GRED=m
+CONFIG_NET_SCH_DSMARK=m
+CONFIG_NET_SCH_NETEM=m
+CONFIG_NET_SCH_DRR=m
+CONFIG_NET_SCH_INGRESS=m
+CONFIG_NET_CLS_BASIC=m
+CONFIG_NET_CLS_TCINDEX=m
+CONFIG_NET_CLS_ROUTE4=m
+CONFIG_NET_CLS_FW=m
+CONFIG_NET_CLS_U32=m
+CONFIG_CLS_U32_PERF=y
+CONFIG_CLS_U32_MARK=y
+CONFIG_NET_CLS_RSVP=m
+CONFIG_NET_CLS_RSVP6=m
+CONFIG_NET_CLS_FLOW=m
CONFIG_NET_EMATCH=y
+CONFIG_NET_EMATCH_CMP=m
+CONFIG_NET_EMATCH_NBYTE=m
+CONFIG_NET_EMATCH_U32=m
+CONFIG_NET_EMATCH_META=m
+CONFIG_NET_EMATCH_TEXT=m
CONFIG_NET_CLS_ACT=y
+CONFIG_NET_ACT_POLICE=m
+CONFIG_NET_ACT_GACT=m
+CONFIG_GACT_PROB=y
+CONFIG_NET_ACT_MIRRED=m
+CONFIG_NET_ACT_IPT=m
+CONFIG_NET_ACT_NAT=m
+CONFIG_NET_ACT_PEDIT=m
+CONFIG_NET_ACT_SIMP=m
+CONFIG_NET_ACT_SKBEDIT=m
+CONFIG_NET_CLS_IND=y
+CONFIG_NET_PKTGEN=m
+CONFIG_CAN=m
+CONFIG_CAN_RAW=m
+CONFIG_CAN_BCM=m
+CONFIG_CAN_VCAN=m
+CONFIG_CAN_DEV=m
+CONFIG_CAN_CALC_BITTIMING=y
+CONFIG_CAN_SJA1000=m
+CONFIG_CAN_SJA1000_ISA=m
+CONFIG_CAN_SJA1000_PLATFORM=m
+CONFIG_CAN_EMS_PCI=m
+CONFIG_CAN_KVASER_PCI=m
+CONFIG_CAN_PLX_PCI=m
+CONFIG_CAN_EMS_USB=m
+CONFIG_CAN_ESD_USB2=m
+CONFIG_IRDA=m
+CONFIG_IRLAN=m
+CONFIG_IRCOMM=m
+CONFIG_IRTTY_SIR=m
+CONFIG_DONGLE=y
+CONFIG_ESI_DONGLE=m
+CONFIG_ACTISYS_DONGLE=m
+CONFIG_TEKRAM_DONGLE=m
+CONFIG_TOIM3232_DONGLE=m
+CONFIG_LITELINK_DONGLE=m
+CONFIG_MA600_DONGLE=m
+CONFIG_GIRBIL_DONGLE=m
+CONFIG_MCP2120_DONGLE=m
+CONFIG_OLD_BELKIN_DONGLE=m
+CONFIG_ACT200L_DONGLE=m
+CONFIG_KINGSUN_DONGLE=m
+CONFIG_KSDAZZLE_DONGLE=m
+CONFIG_KS959_DONGLE=m
+CONFIG_USB_IRDA=m
+CONFIG_SIGMATEL_FIR=m
+CONFIG_VLSI_FIR=m
+CONFIG_MCS_FIR=m
CONFIG_BT=m
CONFIG_BT_L2CAP=y
CONFIG_BT_SCO=y
@@ -95,30 +329,114 @@
CONFIG_BT_BNEP_PROTO_FILTER=y
CONFIG_BT_HIDP=m
CONFIG_BT_HCIBTUSB=m
+CONFIG_BT_HCIBTSDIO=m
+CONFIG_BT_HCIUART=m
+CONFIG_BT_HCIUART_ATH3K=y
+CONFIG_BT_HCIBCM203X=m
+CONFIG_BT_HCIBPA10X=m
CONFIG_BT_HCIBFUSB=m
CONFIG_BT_HCIVHCI=m
+CONFIG_BT_MRVL=m
+CONFIG_BT_MRVL_SDIO=m
+CONFIG_BT_ATH3K=m
CONFIG_CFG80211=m
CONFIG_LIB80211=m
CONFIG_LIB80211_DEBUG=y
CONFIG_MAC80211=m
-CONFIG_MAC80211_LEDS=y
+CONFIG_WIMAX=m
CONFIG_RFKILL=m
-CONFIG_RFKILL_INPUT=y
+CONFIG_CAIF=m
CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
+CONFIG_DEVTMPFS=y
+CONFIG_DEVTMPFS_MOUNT=y
CONFIG_BLK_DEV_LOOP=y
CONFIG_BLK_DEV_CRYPTOLOOP=m
CONFIG_BLK_DEV_RAM=y
CONFIG_BLK_DEV_RAM_SIZE=8192
-# CONFIG_MISC_DEVICES is not set
-CONFIG_IDE=y
-CONFIG_IDE_TASK_IOCTL=y
-# CONFIG_IDEPCI_PCIBUS_ORDER is not set
-CONFIG_BLK_DEV_AMD74XX=y
-CONFIG_SCSI=m
-CONFIG_BLK_DEV_SD=m
+CONFIG_MISC_DEVICES=y
+CONFIG_EEPROM_AT24=m
+CONFIG_EEPROM_LEGACY=m
+CONFIG_BLK_DEV_SD=y
+CONFIG_CHR_DEV_ST=m
+CONFIG_CHR_DEV_OSST=m
+CONFIG_BLK_DEV_SR=m
+CONFIG_BLK_DEV_SR_VENDOR=y
CONFIG_CHR_DEV_SG=m
+CONFIG_CHR_DEV_SCH=m
CONFIG_SCSI_MULTI_LUN=y
-# CONFIG_SCSI_LOWLEVEL is not set
+CONFIG_SCSI_CONSTANTS=y
+CONFIG_SCSI_LOGGING=y
+CONFIG_SCSI_SCAN_ASYNC=y
+CONFIG_SCSI_FC_TGT_ATTRS=y
+CONFIG_SCSI_SAS_ATA=y
+CONFIG_SCSI_SRP_ATTRS=m
+CONFIG_SCSI_SRP_TGT_ATTRS=y
+CONFIG_ISCSI_TCP=m
+CONFIG_SCSI_CXGB3_ISCSI=m
+CONFIG_SCSI_BNX2_ISCSI=m
+CONFIG_BE2ISCSI=m
+CONFIG_BLK_DEV_3W_XXXX_RAID=m
+CONFIG_SCSI_HPSA=m
+CONFIG_SCSI_3W_9XXX=m
+CONFIG_SCSI_3W_SAS=m
+CONFIG_SCSI_ACARD=m
+CONFIG_SCSI_AACRAID=m
+CONFIG_SCSI_AIC7XXX=m
+CONFIG_AIC7XXX_RESET_DELAY_MS=15000
+CONFIG_SCSI_AIC7XXX_OLD=m
+CONFIG_SCSI_AIC79XX=m
+CONFIG_AIC79XX_RESET_DELAY_MS=15000
+CONFIG_SCSI_AIC94XX=m
+# CONFIG_AIC94XX_DEBUG is not set
+CONFIG_SCSI_MVSAS=m
+# CONFIG_SCSI_MVSAS_DEBUG is not set
+CONFIG_MEGARAID_SAS=m
+CONFIG_SCSI_MPT2SAS=m
+CONFIG_SCSI_HPTIOP=m
+CONFIG_FCOE=m
+CONFIG_SCSI_STEX=m
+CONFIG_SCSI_QLA_FC=m
+CONFIG_SCSI_QLA_ISCSI=m
+CONFIG_SCSI_LPFC=m
+CONFIG_SCSI_PMCRAID=m
+CONFIG_SCSI_PM8001=m
+CONFIG_SCSI_SRP=m
+CONFIG_SCSI_BFA_FC=m
+CONFIG_SCSI_DH=m
+CONFIG_SCSI_DH_RDAC=m
+CONFIG_SCSI_DH_HP_SW=m
+CONFIG_SCSI_DH_EMC=m
+CONFIG_SCSI_DH_ALUA=m
+CONFIG_SCSI_OSD_INITIATOR=m
+CONFIG_SCSI_OSD_ULD=m
+CONFIG_ATA=y
+CONFIG_SATA_AHCI=m
+CONFIG_SATA_INIC162X=m
+CONFIG_SATA_SIL24=m
+CONFIG_PDC_ADMA=m
+CONFIG_SATA_QSTOR=m
+CONFIG_SATA_SX4=m
+CONFIG_ATA_PIIX=m
+CONFIG_SATA_MV=m
+CONFIG_SATA_NV=m
+CONFIG_SATA_PROMISE=m
+CONFIG_SATA_SIL=y
+CONFIG_SATA_SIS=m
+CONFIG_SATA_SVW=m
+CONFIG_SATA_ULI=m
+CONFIG_SATA_VIA=m
+CONFIG_SATA_VITESSE=m
+CONFIG_PATA_ARTOP=m
+CONFIG_PATA_ATP867X=m
+CONFIG_PATA_CMD64X=m
+CONFIG_PATA_CS5536=y
+CONFIG_PATA_IT821X=m
+CONFIG_PATA_JMICRON=m
+CONFIG_PATA_MARVELL=m
+CONFIG_PATA_RDC=m
+CONFIG_PATA_SCH=m
+CONFIG_PATA_TOSHIBA=m
+CONFIG_ATA_GENERIC=m
CONFIG_MD=y
CONFIG_BLK_DEV_MD=m
CONFIG_MD_LINEAR=m
@@ -129,7 +447,6 @@
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
@@ -140,55 +457,192 @@
CONFIG_DM_MULTIPATH_ST=m
CONFIG_DM_DELAY=m
CONFIG_DM_UEVENT=y
-CONFIG_NETDEVICES=y
+CONFIG_FUSION=y
+CONFIG_FUSION_SPI=m
+CONFIG_FUSION_FC=m
+CONFIG_FUSION_SAS=m
+CONFIG_FUSION_MAX_SGE=40
+CONFIG_FUSION_CTL=m
CONFIG_DUMMY=m
+CONFIG_BONDING=m
+CONFIG_MACVLAN=m
CONFIG_TUN=m
CONFIG_VETH=m
+CONFIG_MII=y
CONFIG_NET_ETHERNET=y
CONFIG_NET_PCI=y
-CONFIG_8139TOO=y
-# CONFIG_8139TOO_PIO is not set
-CONFIG_R8169=y
-CONFIG_R8169_VLAN=y
-# CONFIG_NETDEV_10000 is not set
-CONFIG_USB_USBNET=m
+CONFIG_8139TOO=m
+CONFIG_R8169=m
+CONFIG_AT76C50X_USB=m
+CONFIG_USB_ZD1201=m
+CONFIG_USB_NET_RNDIS_WLAN=m
+CONFIG_RTL8187B=m
+CONFIG_ATH_COMMON=m
+CONFIG_AR9170_USB=m
+CONFIG_RT2X00=m
+CONFIG_RT2500USB=m
+CONFIG_RT73USB=m
+CONFIG_RT2800USB=m
+CONFIG_RT2800USB_RT35XX=y
+CONFIG_RT2800USB_UNKNOWN=y
+CONFIG_ZD1211RW=m
+CONFIG_USB_CATC=m
+CONFIG_USB_KAWETH=m
+CONFIG_USB_PEGASUS=m
+CONFIG_USB_RTL8150=m
CONFIG_USB_NET_CDC_EEM=m
+CONFIG_USB_NET_DM9601=m
+CONFIG_USB_NET_SMSC75XX=m
+CONFIG_USB_NET_SMSC95XX=m
+CONFIG_USB_NET_GL620A=m
+CONFIG_USB_NET_PLUSB=m
+CONFIG_USB_NET_MCS7830=m
+CONFIG_USB_ALI_M5632=y
+CONFIG_USB_AN2720=y
+CONFIG_USB_EPSON2888=y
+CONFIG_USB_KC2190=y
+CONFIG_USB_HSO=m
+CONFIG_USB_NET_INT51X1=m
+CONFIG_USB_IPHETH=m
+CONFIG_USB_SIERRA_NET=m
+CONFIG_WAN=y
+CONFIG_LANMEDIA=m
+CONFIG_HDLC=m
+CONFIG_HDLC_RAW=m
+CONFIG_HDLC_RAW_ETH=m
+CONFIG_HDLC_CISCO=m
+CONFIG_HDLC_FR=m
+CONFIG_HDLC_PPP=m
+CONFIG_PCI200SYN=m
+CONFIG_WANXL=m
+CONFIG_PC300TOO=m
+CONFIG_N2=m
+CONFIG_C101=m
+CONFIG_FARSYNC=m
+CONFIG_DSCC4=m
+CONFIG_DLCI=m
+CONFIG_SDLA=m
+CONFIG_ATM_DUMMY=m
+CONFIG_ATM_TCP=m
+CONFIG_ATM_LANAI=m
+CONFIG_ATM_ENI=m
+CONFIG_ATM_ENI_DEBUG=y
+CONFIG_CAIF_TTY=m
+CONFIG_CAIF_SPI_SLAVE=m
+CONFIG_PPP=m
+CONFIG_PPP_ASYNC=m
+CONFIG_PPP_SYNC_TTY=m
+CONFIG_PPP_DEFLATE=m
+CONFIG_PPP_BSDCOMP=m
+CONFIG_PPP_MPPE=m
+CONFIG_PPPOE=m
+CONFIG_PPPOATM=m
+CONFIG_PPPOL2TP=m
+CONFIG_SLIP=m
+CONFIG_SLIP_SMART=y
+CONFIG_SLIP_MODE_SLIP6=y
+CONFIG_NET_FC=y
CONFIG_NETCONSOLE=m
-CONFIG_NETCONSOLE_DYNAMIC=y
-CONFIG_INPUT_POLLDEV=m
+CONFIG_NETPOLL_TRAP=y
+CONFIG_VMXNET3=m
+CONFIG_PHONE=m
+CONFIG_PHONE_IXJ=m
CONFIG_INPUT_EVDEV=y
-# CONFIG_MOUSE_PS2_ALPS is not set
-# CONFIG_MOUSE_PS2_LOGIPS2PP is not set
-# CONFIG_MOUSE_PS2_TRACKPOINT is not set
+CONFIG_KEYBOARD_LKKBD=m
+CONFIG_KEYBOARD_NEWTON=m
+CONFIG_KEYBOARD_OPENCORES=m
+CONFIG_KEYBOARD_STOWAWAY=m
+CONFIG_KEYBOARD_SUNKBD=m
+CONFIG_KEYBOARD_XTKBD=m
CONFIG_MOUSE_APPLETOUCH=m
-# CONFIG_SERIO_SERPORT is not set
-CONFIG_SERIAL_NONSTANDARD=y
+CONFIG_MOUSE_BCM5974=m
+CONFIG_INPUT_TABLET=y
+CONFIG_TABLET_USB_ACECAD=m
+CONFIG_TABLET_USB_AIPTEK=m
+CONFIG_TABLET_USB_GTCO=m
+CONFIG_TABLET_USB_KBTAB=m
+CONFIG_TABLET_USB_WACOM=m
+CONFIG_INPUT_TOUCHSCREEN=y
+CONFIG_TOUCHSCREEN_AD7879=m
+CONFIG_TOUCHSCREEN_DYNAPRO=m
+CONFIG_TOUCHSCREEN_HAMPSHIRE=m
+CONFIG_TOUCHSCREEN_FUJITSU=m
+CONFIG_TOUCHSCREEN_GUNZE=m
+CONFIG_TOUCHSCREEN_ELO=m
+CONFIG_TOUCHSCREEN_WACOM_W8001=m
+CONFIG_TOUCHSCREEN_MTOUCH=m
+CONFIG_TOUCHSCREEN_INEXIO=m
+CONFIG_TOUCHSCREEN_MK712=m
+CONFIG_TOUCHSCREEN_HTCPEN=m
+CONFIG_TOUCHSCREEN_PENMOUNT=m
+CONFIG_TOUCHSCREEN_TOUCHRIGHT=m
+CONFIG_TOUCHSCREEN_TOUCHWIN=m
+CONFIG_TOUCHSCREEN_WM97XX=m
+CONFIG_TOUCHSCREEN_USB_COMPOSITE=m
+CONFIG_TOUCHSCREEN_TOUCHIT213=m
+CONFIG_INPUT_MISC=y
+CONFIG_INPUT_AD714X=m
+CONFIG_INPUT_ATI_REMOTE=m
+CONFIG_INPUT_ATI_REMOTE2=m
+CONFIG_INPUT_KEYSPAN_REMOTE=m
+CONFIG_INPUT_YEALINK=m
+CONFIG_INPUT_CM109=m
+CONFIG_INPUT_ADXL34X=m
+CONFIG_LEGACY_PTY_COUNT=16
+CONFIG_NOZOMI=m
+CONFIG_N_GSM=m
CONFIG_SERIAL_8250=m
-# CONFIG_SERIAL_8250_PCI is not set
CONFIG_SERIAL_8250_NR_UARTS=16
CONFIG_SERIAL_8250_EXTENDED=y
CONFIG_SERIAL_8250_MANY_PORTS=y
CONFIG_SERIAL_8250_FOURPORT=y
-CONFIG_LEGACY_PTY_COUNT=16
CONFIG_HW_RANDOM=y
CONFIG_RTC=y
+CONFIG_I2C=m
+CONFIG_I2C_CHARDEV=m
+CONFIG_I2C_MUX=m
+CONFIG_I2C_MUX_PCA954x=m
+CONFIG_I2C_OCORES=m
+CONFIG_I2C_PARPORT_LIGHT=m
+CONFIG_I2C_TINY_USB=m
+CONFIG_SCx200_ACB=m
+CONFIG_SPI=y
+CONFIG_W1=m
+CONFIG_W1_MASTER_DS2490=m
+CONFIG_W1_SLAVE_THERM=m
+CONFIG_W1_SLAVE_SMEM=m
+CONFIG_W1_SLAVE_DS2431=m
+CONFIG_W1_SLAVE_DS2433=m
+CONFIG_W1_SLAVE_DS2433_CRC=y
+CONFIG_W1_SLAVE_DS2760=m
+CONFIG_W1_SLAVE_BQ27000=m
CONFIG_THERMAL=y
+CONFIG_WATCHDOG=y
+CONFIG_SOFT_WATCHDOG=m
+CONFIG_USBPCWATCHDOG=m
CONFIG_MEDIA_SUPPORT=m
CONFIG_VIDEO_DEV=m
-CONFIG_VIDEO_HELPER_CHIPS_AUTO=y
+CONFIG_DVB_CORE=m
CONFIG_VIDEO_VIVI=m
CONFIG_USB_VIDEO_CLASS=m
CONFIG_USB_M5602=m
CONFIG_USB_STV06XX=m
+CONFIG_USB_GL860=m
+CONFIG_USB_GSPCA_BENQ=m
CONFIG_USB_GSPCA_CONEX=m
+CONFIG_USB_GSPCA_CPIA1=m
CONFIG_USB_GSPCA_ETOMS=m
CONFIG_USB_GSPCA_FINEPIX=m
+CONFIG_USB_GSPCA_JEILINJ=m
CONFIG_USB_GSPCA_MARS=m
CONFIG_USB_GSPCA_MR97310A=m
CONFIG_USB_GSPCA_OV519=m
CONFIG_USB_GSPCA_OV534=m
+CONFIG_USB_GSPCA_OV534_9=m
CONFIG_USB_GSPCA_PAC207=m
+CONFIG_USB_GSPCA_PAC7302=m
CONFIG_USB_GSPCA_PAC7311=m
+CONFIG_USB_GSPCA_SN9C2028=m
CONFIG_USB_GSPCA_SN9C20X=m
CONFIG_USB_GSPCA_SONIXB=m
CONFIG_USB_GSPCA_SONIXJ=m
@@ -198,30 +652,72 @@
CONFIG_USB_GSPCA_SPCA506=m
CONFIG_USB_GSPCA_SPCA508=m
CONFIG_USB_GSPCA_SPCA561=m
+CONFIG_USB_GSPCA_SPCA1528=m
CONFIG_USB_GSPCA_SQ905=m
CONFIG_USB_GSPCA_SQ905C=m
+CONFIG_USB_GSPCA_SQ930X=m
CONFIG_USB_GSPCA_STK014=m
+CONFIG_USB_GSPCA_STV0680=m
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_PVRUSB2=m
+CONFIG_VIDEO_PVRUSB2_DEBUGIFC=y
+CONFIG_VIDEO_HDPVR=m
+CONFIG_VIDEO_EM28XX=m
+CONFIG_VIDEO_EM28XX_ALSA=m
+CONFIG_VIDEO_CX231XX=m
+CONFIG_VIDEO_CX231XX_ALSA=m
+CONFIG_VIDEO_USBVISION=m
CONFIG_USB_ET61X251=m
CONFIG_USB_SN9C102=m
+CONFIG_USB_PWC=m
CONFIG_USB_ZR364XX=m
CONFIG_USB_STKWEBCAM=m
CONFIG_USB_S2255=m
-# CONFIG_RADIO_ADAPTERS is not set
+CONFIG_USB_DSBR=m
+CONFIG_USB_MR800=m
+CONFIG_DVB_USB=m
+CONFIG_DVB_USB_A800=m
+CONFIG_DVB_USB_DIBUSB_MB=m
+CONFIG_DVB_USB_DIBUSB_MB_FAULTY=y
+CONFIG_DVB_USB_DIBUSB_MC=m
+CONFIG_DVB_USB_DIB0700=m
+CONFIG_DVB_USB_UMT_010=m
+CONFIG_DVB_USB_CXUSB=m
+CONFIG_DVB_USB_M920X=m
+CONFIG_DVB_USB_GL861=m
+CONFIG_DVB_USB_AU6610=m
+CONFIG_DVB_USB_DIGITV=m
+CONFIG_DVB_USB_VP7045=m
+CONFIG_DVB_USB_VP702X=m
+CONFIG_DVB_USB_GP8PSK=m
+CONFIG_DVB_USB_NOVA_T_USB2=m
+CONFIG_DVB_USB_TTUSB2=m
+CONFIG_DVB_USB_DTT200U=m
+CONFIG_DVB_USB_OPERA1=m
+CONFIG_DVB_USB_AF9005=m
+CONFIG_DVB_USB_DW2102=m
+CONFIG_DVB_USB_CINERGY_T2=m
+CONFIG_DVB_USB_ANYSEE=m
+CONFIG_DVB_USB_DTV5100=m
+CONFIG_DVB_USB_AF9015=m
+CONFIG_DVB_USB_CE6230=m
+CONFIG_DVB_USB_FRIIO=m
+CONFIG_DVB_USB_EC168=m
+CONFIG_DVB_USB_AZ6027=m
+CONFIG_DVB_TTUSB_BUDGET=m
+CONFIG_DVB_TTUSB_DEC=m
CONFIG_VIDEO_OUTPUT_CONTROL=y
CONFIG_FB=y
CONFIG_FIRMWARE_EDID=y
-CONFIG_FB_MODE_HELPERS=y
CONFIG_FB_TILEBLITTING=y
CONFIG_FB_SIS=y
CONFIG_FB_SIS_300=y
CONFIG_FB_SIS_315=y
-CONFIG_BACKLIGHT_LCD_SUPPORT=y
-# CONFIG_LCD_CLASS_DEVICE is not set
+CONFIG_FB_UDL=m
CONFIG_BACKLIGHT_CLASS_DEVICE=y
CONFIG_BACKLIGHT_GENERIC=m
# CONFIG_VGA_CONSOLE is not set
@@ -238,8 +734,6 @@
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_SOUND=m
CONFIG_SND=m
CONFIG_SND_SEQUENCER=m
@@ -255,30 +749,18 @@
CONFIG_SND_AC97_POWER_SAVE=y
CONFIG_SND_AC97_POWER_SAVE_DEFAULT=10
CONFIG_SND_CS5535AUDIO=m
-# CONFIG_SND_MIPS is not set
CONFIG_SND_USB_AUDIO=m
CONFIG_SND_USB_CAIAQ=m
CONFIG_SND_USB_CAIAQ_INPUT=y
CONFIG_HIDRAW=y
+CONFIG_USB_HID=m
CONFIG_USB_HIDDEV=y
-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
@@ -293,19 +775,14 @@
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=y
-CONFIG_USB_DEVICEFS=y
-# CONFIG_USB_DEVICE_CLASS is not set
CONFIG_USB_DYNAMIC_MINORS=y
CONFIG_USB_SUSPEND=y
-CONFIG_USB_OTG_WHITELIST=y
-CONFIG_USB_MON=y
+CONFIG_USB_MON=m
CONFIG_USB_EHCI_HCD=y
CONFIG_USB_EHCI_ROOT_HUB_TT=y
-# CONFIG_USB_EHCI_TT_NEWSCHED is not set
CONFIG_USB_OHCI_HCD=y
CONFIG_USB_UHCI_HCD=m
CONFIG_USB_WHCI_HCD=m
@@ -313,7 +790,7 @@
CONFIG_USB_ACM=m
CONFIG_USB_PRINTER=m
CONFIG_USB_WDM=m
-CONFIG_USB_STORAGE=m
+CONFIG_USB_STORAGE=y
CONFIG_USB_STORAGE_DATAFAB=m
CONFIG_USB_STORAGE_FREECOM=m
CONFIG_USB_STORAGE_ISD200=m
@@ -322,22 +799,123 @@
CONFIG_USB_STORAGE_SDDR55=m
CONFIG_USB_STORAGE_JUMPSHOT=m
CONFIG_USB_STORAGE_ALAUDA=m
+CONFIG_USB_STORAGE_ONETOUCH=m
+CONFIG_USB_STORAGE_KARMA=m
+CONFIG_USB_STORAGE_CYPRESS_ATACB=m
CONFIG_USB_LIBUSUAL=y
+CONFIG_USB_MDC800=m
+CONFIG_USB_MICROTEK=m
CONFIG_USB_SERIAL=m
CONFIG_USB_SERIAL_GENERIC=y
+CONFIG_USB_SERIAL_AIRCABLE=m
+CONFIG_USB_SERIAL_ARK3116=m
+CONFIG_USB_SERIAL_BELKIN=m
+CONFIG_USB_SERIAL_CH341=m
+CONFIG_USB_SERIAL_WHITEHEAT=m
+CONFIG_USB_SERIAL_DIGI_ACCELEPORT=m
+CONFIG_USB_SERIAL_CP210X=m
+CONFIG_USB_SERIAL_CYPRESS_M8=m
+CONFIG_USB_SERIAL_EMPEG=m
+CONFIG_USB_SERIAL_FTDI_SIO=m
+CONFIG_USB_SERIAL_FUNSOFT=m
+CONFIG_USB_SERIAL_VISOR=m
+CONFIG_USB_SERIAL_IPAQ=m
+CONFIG_USB_SERIAL_IR=m
+CONFIG_USB_SERIAL_EDGEPORT=m
+CONFIG_USB_SERIAL_EDGEPORT_TI=m
+CONFIG_USB_SERIAL_GARMIN=m
+CONFIG_USB_SERIAL_IPW=m
+CONFIG_USB_SERIAL_IUU=m
+CONFIG_USB_SERIAL_KEYSPAN_PDA=m
+CONFIG_USB_SERIAL_KEYSPAN=m
+CONFIG_USB_SERIAL_KEYSPAN_MPR=y
+CONFIG_USB_SERIAL_KEYSPAN_USA28=y
+CONFIG_USB_SERIAL_KEYSPAN_USA28X=y
+CONFIG_USB_SERIAL_KEYSPAN_USA28XA=y
+CONFIG_USB_SERIAL_KEYSPAN_USA28XB=y
+CONFIG_USB_SERIAL_KEYSPAN_USA19=y
+CONFIG_USB_SERIAL_KEYSPAN_USA18X=y
+CONFIG_USB_SERIAL_KEYSPAN_USA19W=y
+CONFIG_USB_SERIAL_KEYSPAN_USA19QW=y
+CONFIG_USB_SERIAL_KEYSPAN_USA19QI=y
+CONFIG_USB_SERIAL_KEYSPAN_USA49W=y
+CONFIG_USB_SERIAL_KEYSPAN_USA49WLC=y
+CONFIG_USB_SERIAL_KLSI=m
+CONFIG_USB_SERIAL_KOBIL_SCT=m
+CONFIG_USB_SERIAL_MCT_U232=m
+CONFIG_USB_SERIAL_MOS7720=m
+CONFIG_USB_SERIAL_MOS7840=m
+CONFIG_USB_SERIAL_MOTOROLA=m
+CONFIG_USB_SERIAL_NAVMAN=m
+CONFIG_USB_SERIAL_PL2303=m
+CONFIG_USB_SERIAL_OTI6858=m
+CONFIG_USB_SERIAL_QCAUX=m
+CONFIG_USB_SERIAL_QUALCOMM=m
+CONFIG_USB_SERIAL_SPCP8X5=m
+CONFIG_USB_SERIAL_HP4X=m
+CONFIG_USB_SERIAL_SAFE=m
+CONFIG_USB_SERIAL_SAFE_PADDED=y
+CONFIG_USB_SERIAL_SIEMENS_MPI=m
+CONFIG_USB_SERIAL_SIERRAWIRELESS=m
+CONFIG_USB_SERIAL_SYMBOL=m
+CONFIG_USB_SERIAL_TI=m
+CONFIG_USB_SERIAL_CYBERJACK=m
+CONFIG_USB_SERIAL_XIRCOM=m
+CONFIG_USB_SERIAL_OPTION=m
+CONFIG_USB_SERIAL_OMNINET=m
+CONFIG_USB_SERIAL_OPTICON=m
+CONFIG_USB_SERIAL_VIVOPAY_SERIAL=m
+CONFIG_USB_SERIAL_ZIO=m
+CONFIG_USB_SERIAL_SSU100=m
+CONFIG_USB_EMI62=m
+CONFIG_USB_EMI26=m
+CONFIG_USB_ADUTUX=m
+CONFIG_USB_SEVSEG=m
+CONFIG_USB_RIO500=m
+CONFIG_USB_LEGOTOWER=m
+CONFIG_USB_LCD=m
CONFIG_USB_LED=m
+CONFIG_USB_CYPRESS_CY7C63=m
+CONFIG_USB_CYTHERM=m
+CONFIG_USB_IDMOUSE=m
+CONFIG_USB_FTDI_ELAN=m
+CONFIG_USB_APPLEDISPLAY=m
+CONFIG_USB_SISUSBVGA=m
+CONFIG_USB_LD=m
+CONFIG_USB_TRANCEVIBRATOR=m
+CONFIG_USB_IOWARRIOR=m
+CONFIG_USB_ISIGHTFW=m
+CONFIG_USB_ATM=m
+CONFIG_USB_SPEEDTOUCH=m
+CONFIG_USB_CXACRU=m
+CONFIG_USB_UEAGLEATM=m
+CONFIG_USB_XUSBATM=m
CONFIG_USB_GADGET=m
CONFIG_USB_GADGET_M66592=y
+CONFIG_USB_ZERO=m
+CONFIG_USB_AUDIO=m
+CONFIG_USB_ETH=m
+CONFIG_USB_GADGETFS=m
+CONFIG_USB_FUNCTIONFS=m
+CONFIG_USB_MASS_STORAGE=m
+CONFIG_USB_G_SERIAL=m
+CONFIG_USB_MIDI_GADGET=m
+CONFIG_USB_G_PRINTER=m
+CONFIG_USB_CDC_COMPOSITE=m
+CONFIG_USB_G_MULTI=m
+CONFIG_USB_G_WEBCAM=m
+CONFIG_NOP_USB_XCEIV=m
CONFIG_MMC=m
CONFIG_LEDS_CLASS=y
CONFIG_STAGING=y
# CONFIG_STAGING_EXCLUDE_BUILD is not set
+CONFIG_PRISM2_USB=m
+CONFIG_R8187SE=m
+CONFIG_RTL8192E=m
+CONFIG_USB_SERIAL_QUATECH2=m
+CONFIG_USB_SERIAL_QUATECH_USB2=m
CONFIG_FB_SM7XX=y
-CONFIG_EXT2_FS=m
-CONFIG_EXT3_FS=y
-# CONFIG_EXT3_DEFAULTS_TO_ORDERED is not set
-CONFIG_EXT3_FS_POSIX_ACL=y
-CONFIG_EXT3_FS_SECURITY=y
+CONFIG_EASYCAP=m
CONFIG_EXT4_FS=y
CONFIG_REISERFS_FS=m
CONFIG_REISERFS_PROC_INFO=y
@@ -347,16 +925,17 @@
CONFIG_XFS_FS=m
CONFIG_XFS_QUOTA=y
CONFIG_XFS_POSIX_ACL=y
-CONFIG_BTRFS_FS=m
-CONFIG_QUOTA=y
-CONFIG_QFMT_V2=m
-CONFIG_AUTOFS_FS=m
+CONFIG_GFS2_FS=m
+CONFIG_BTRFS_FS=y
CONFIG_AUTOFS4_FS=m
+CONFIG_FUSE_FS=m
+CONFIG_CUSE=m
CONFIG_FSCACHE=m
CONFIG_CACHEFILES=m
CONFIG_ISO9660_FS=m
CONFIG_JOLIET=y
CONFIG_ZISOFS=y
+CONFIG_UDF_FS=m
CONFIG_MSDOS_FS=m
CONFIG_VFAT_FS=m
CONFIG_NTFS_FS=m
@@ -367,6 +946,7 @@
CONFIG_SQUASHFS=m
CONFIG_SQUASHFS_EMBEDDED=y
CONFIG_ROMFS_FS=m
+CONFIG_UFS_FS=m
CONFIG_NFS_FS=m
CONFIG_NFS_V3=y
CONFIG_NFS_V3_ACL=y
@@ -412,15 +992,15 @@
CONFIG_NLS_KOI8_R=m
CONFIG_NLS_KOI8_U=m
CONFIG_NLS_UTF8=y
-CONFIG_PRINTK_TIME=y
CONFIG_FRAME_WARN=1024
+CONFIG_MAGIC_SYSRQ=y
CONFIG_STRIP_ASM_SYMS=y
CONFIG_DEBUG_FS=y
-# CONFIG_RCU_CPU_STALL_DETECTOR is not set
+CONFIG_DEBUG_KERNEL=y
+CONFIG_TIMER_STATS=y
CONFIG_SYSCTL_SYSCALL_CHECK=y
CONFIG_KEYS=y
CONFIG_KEYS_DEBUG_PROC_KEYS=y
-CONFIG_CRYPTO_FIPS=y
CONFIG_CRYPTO_NULL=m
CONFIG_CRYPTO_CRYPTD=m
CONFIG_CRYPTO_AUTHENC=m
@@ -430,15 +1010,12 @@
CONFIG_CRYPTO_LRW=m
CONFIG_CRYPTO_PCBC=m
CONFIG_CRYPTO_XTS=m
-CONFIG_CRYPTO_HMAC=m
CONFIG_CRYPTO_XCBC=m
-CONFIG_CRYPTO_MD4=m
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
@@ -458,4 +1035,3 @@
CONFIG_CRYPTO_DEFLATE=m
CONFIG_CRYPTO_ZLIB=m
CONFIG_CRYPTO_LZO=m
-CONFIG_CRC_T10DIF=y
diff --git a/arch/mips/configs/lemote2f_minimal_defconfig b/arch/mips/configs/lemote2f_minimal_defconfig
new file mode 100644
index 0000000..82ad0bd4
--- /dev/null
+++ b/arch/mips/configs/lemote2f_minimal_defconfig
@@ -0,0 +1,122 @@
+CONFIG_MACH_LOONGSON=y
+CONFIG_LEMOTE_MACH2F=y
+CONFIG_64BIT=y
+CONFIG_NO_HZ=y
+CONFIG_HIGH_RES_TIMERS=y
+CONFIG_PREEMPT=y
+CONFIG_EXPERIMENTAL=y
+# CONFIG_LOCALVERSION_AUTO is not set
+CONFIG_KERNEL_LZMA=y
+CONFIG_SYSVIPC=y
+CONFIG_POSIX_MQUEUE=y
+CONFIG_BSD_PROCESS_ACCT=y
+CONFIG_BSD_PROCESS_ACCT_V3=y
+CONFIG_IKCONFIG=y
+CONFIG_IKCONFIG_PROC=y
+CONFIG_LOG_BUF_SHIFT=15
+CONFIG_BLK_DEV_INITRD=y
+# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
+# CONFIG_BLK_DEV_BSG is not set
+# CONFIG_IOSCHED_DEADLINE is not set
+# CONFIG_IOSCHED_CFQ is not set
+CONFIG_PCI=y
+CONFIG_MIPS32_COMPAT=y
+CONFIG_MIPS32_O32=y
+CONFIG_MIPS32_N32=y
+CONFIG_NET=y
+CONFIG_PACKET=y
+CONFIG_UNIX=y
+CONFIG_INET=y
+# CONFIG_INET_XFRM_MODE_TRANSPORT is not set
+# CONFIG_INET_XFRM_MODE_TUNNEL is not set
+# CONFIG_INET_XFRM_MODE_BEET is not set
+# CONFIG_INET_LRO is not set
+# CONFIG_INET_DIAG is not set
+# CONFIG_IPV6 is not set
+# CONFIG_WIRELESS is not set
+CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
+CONFIG_DEVTMPFS=y
+CONFIG_DEVTMPFS_MOUNT=y
+CONFIG_BLK_DEV_LOOP=y
+CONFIG_BLK_DEV_RAM=y
+CONFIG_BLK_DEV_RAM_SIZE=8192
+# CONFIG_MISC_DEVICES is not set
+# CONFIG_SCSI_PROC_FS is not set
+CONFIG_BLK_DEV_SD=y
+# CONFIG_SCSI_LOWLEVEL is not set
+CONFIG_ATA=y
+# CONFIG_SATA_PMP is not set
+CONFIG_PATA_AMD=y
+CONFIG_NETDEVICES=y
+CONFIG_NET_ETHERNET=y
+CONFIG_NET_PCI=y
+CONFIG_8139TOO=y
+CONFIG_R8169=y
+# CONFIG_NETDEV_10000 is not set
+# CONFIG_WLAN is not set
+# CONFIG_INPUT_MOUSEDEV_PSAUX is not set
+CONFIG_INPUT_EVDEV=y
+# CONFIG_SERIO_SERPORT is not set
+# CONFIG_DEVKMEM is not set
+CONFIG_SERIAL_8250=y
+CONFIG_SERIAL_8250_CONSOLE=y
+CONFIG_LEGACY_PTY_COUNT=16
+# CONFIG_HW_RANDOM is not set
+# CONFIG_HWMON is not set
+# CONFIG_MFD_SUPPORT is not set
+CONFIG_FB=y
+CONFIG_FB_SIS=y
+CONFIG_FB_SIS_300=y
+CONFIG_FB_SIS_315=y
+# CONFIG_VGA_CONSOLE is not set
+CONFIG_FRAMEBUFFER_CONSOLE=y
+CONFIG_HIDRAW=y
+CONFIG_USB_HIDDEV=y
+CONFIG_HID_DRAGONRISE=y
+CONFIG_DRAGONRISE_FF=y
+CONFIG_HID_GYRATION=y
+CONFIG_HID_TWINHAN=y
+CONFIG_LOGITECH_FF=y
+CONFIG_LOGIRUMBLEPAD2_FF=y
+CONFIG_HID_NTRIG=y
+CONFIG_HID_PANTHERLORD=y
+CONFIG_PANTHERLORD_FF=y
+CONFIG_HID_PETALYNX=y
+CONFIG_HID_SAMSUNG=y
+CONFIG_HID_SONY=y
+CONFIG_HID_SUNPLUS=y
+CONFIG_HID_GREENASIA=y
+CONFIG_GREENASIA_FF=y
+CONFIG_HID_SMARTJOYPLUS=y
+CONFIG_SMARTJOYPLUS_FF=y
+CONFIG_HID_TOPSEED=y
+CONFIG_HID_THRUSTMASTER=y
+CONFIG_THRUSTMASTER_FF=y
+CONFIG_HID_ZEROPLUS=y
+CONFIG_ZEROPLUS_FF=y
+CONFIG_USB=y
+# CONFIG_USB_DEVICE_CLASS is not set
+CONFIG_USB_DYNAMIC_MINORS=y
+CONFIG_USB_MON=y
+CONFIG_USB_EHCI_HCD=y
+CONFIG_USB_EHCI_ROOT_HUB_TT=y
+# CONFIG_USB_EHCI_TT_NEWSCHED is not set
+CONFIG_USB_OHCI_HCD=y
+CONFIG_USB_STORAGE=y
+CONFIG_USB_LIBUSUAL=y
+CONFIG_RTC_CLASS=y
+CONFIG_RTC_DRV_CMOS=y
+CONFIG_STAGING=y
+# CONFIG_STAGING_EXCLUDE_BUILD is not set
+CONFIG_FB_SM7XX=y
+# CONFIG_MIPS_PLATFORM_DEVICES is not set
+CONFIG_EXT4_FS=y
+CONFIG_TMPFS=y
+# CONFIG_MISC_FILESYSTEMS is not set
+# CONFIG_NETWORK_FILESYSTEMS is not set
+CONFIG_NLS_DEFAULT="utf8"
+CONFIG_NLS_ASCII=y
+CONFIG_NLS_UTF8=y
+CONFIG_FRAME_WARN=1024
+CONFIG_STRIP_ASM_SYMS=y
+# CONFIG_RCU_CPU_STALL_DETECTOR is not set
diff --git a/arch/mips/configs/lemote2f_small_defconfig b/arch/mips/configs/lemote2f_small_defconfig
new file mode 100644
index 0000000..a546502
--- /dev/null
+++ b/arch/mips/configs/lemote2f_small_defconfig
@@ -0,0 +1,152 @@
+CONFIG_MACH_LOONGSON=y
+CONFIG_LEMOTE_MACH2F=y
+CONFIG_64BIT=y
+CONFIG_NO_HZ=y
+CONFIG_HIGH_RES_TIMERS=y
+CONFIG_PREEMPT=y
+CONFIG_EXPERIMENTAL=y
+# CONFIG_LOCALVERSION_AUTO is not set
+CONFIG_KERNEL_LZMA=y
+CONFIG_SYSVIPC=y
+CONFIG_POSIX_MQUEUE=y
+CONFIG_BSD_PROCESS_ACCT=y
+CONFIG_BSD_PROCESS_ACCT_V3=y
+CONFIG_IKCONFIG=y
+CONFIG_IKCONFIG_PROC=y
+CONFIG_LOG_BUF_SHIFT=15
+# CONFIG_UTS_NS is not set
+# CONFIG_IPC_NS is not set
+# CONFIG_USER_NS is not set
+# CONFIG_PID_NS is not set
+# CONFIG_NET_NS is not set
+CONFIG_BLK_DEV_INITRD=y
+# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
+CONFIG_MODULES=y
+CONFIG_MODULE_UNLOAD=y
+# CONFIG_BLK_DEV_BSG is not set
+# CONFIG_IOSCHED_DEADLINE is not set
+# CONFIG_IOSCHED_CFQ is not set
+CONFIG_PCI=y
+# CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS is not set
+CONFIG_MIPS32_COMPAT=y
+CONFIG_MIPS32_O32=y
+CONFIG_MIPS32_N32=y
+CONFIG_PM=y
+CONFIG_HIBERNATION=y
+CONFIG_PM_STD_PARTITION="/dev/sda3"
+CONFIG_PM_RUNTIME=y
+CONFIG_R4K_TIMER_FOR_CPUFREQ=y
+CONFIG_CPU_FREQ=y
+CONFIG_CPU_FREQ_STAT_DETAILS=y
+CONFIG_CPU_FREQ_DEFAULT_GOV_CONSERVATIVE=y
+CONFIG_CPU_FREQ_GOV_POWERSAVE=y
+CONFIG_CPU_FREQ_GOV_USERSPACE=y
+CONFIG_CPU_FREQ_GOV_ONDEMAND=y
+CONFIG_LOONGSON2_CPUFREQ=m
+CONFIG_NET=y
+CONFIG_PACKET=y
+CONFIG_UNIX=y
+CONFIG_INET=y
+# CONFIG_INET_XFRM_MODE_TRANSPORT is not set
+# CONFIG_INET_XFRM_MODE_TUNNEL is not set
+# CONFIG_INET_XFRM_MODE_BEET is not set
+# CONFIG_INET_LRO is not set
+# CONFIG_INET_DIAG is not set
+# CONFIG_IPV6 is not set
+CONFIG_CFG80211=y
+# CONFIG_CFG80211_DEFAULT_PS is not set
+# CONFIG_CFG80211_WEXT is not set
+CONFIG_LIB80211=y
+CONFIG_MAC80211=y
+CONFIG_RFKILL=y
+CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
+CONFIG_DEVTMPFS=y
+CONFIG_DEVTMPFS_MOUNT=y
+CONFIG_BLK_DEV_LOOP=y
+CONFIG_BLK_DEV_RAM=y
+CONFIG_BLK_DEV_RAM_SIZE=8192
+# CONFIG_SCSI_PROC_FS is not set
+CONFIG_BLK_DEV_SD=y
+# CONFIG_SCSI_LOWLEVEL is not set
+CONFIG_ATA=y
+# CONFIG_SATA_PMP is not set
+CONFIG_PATA_AMD=y
+CONFIG_NETDEVICES=y
+CONFIG_NET_ETHERNET=y
+CONFIG_NET_PCI=y
+CONFIG_8139TOO=y
+CONFIG_R8169=y
+# CONFIG_NETDEV_10000 is not set
+CONFIG_RTL8187B=m
+# CONFIG_INPUT_MOUSEDEV_PSAUX is not set
+CONFIG_INPUT_EVDEV=y
+# CONFIG_SERIO_SERPORT is not set
+# CONFIG_DEVKMEM is not set
+CONFIG_SERIAL_8250=y
+CONFIG_SERIAL_8250_CONSOLE=y
+CONFIG_LEGACY_PTY_COUNT=16
+# CONFIG_HW_RANDOM is not set
+CONFIG_HWMON=m
+# CONFIG_MFD_SUPPORT is not set
+CONFIG_FB=y
+CONFIG_FB_SIS=y
+CONFIG_FB_SIS_300=y
+CONFIG_FB_SIS_315=y
+CONFIG_LCD_CLASS_DEVICE=y
+CONFIG_LCD_PLATFORM=y
+CONFIG_BACKLIGHT_CLASS_DEVICE=y
+# CONFIG_BACKLIGHT_GENERIC is not set
+# CONFIG_VGA_CONSOLE is not set
+CONFIG_FRAMEBUFFER_CONSOLE=y
+CONFIG_SOUND=y
+CONFIG_SND=y
+CONFIG_SND_CS5535AUDIO=m
+CONFIG_HIDRAW=y
+CONFIG_USB_HIDDEV=y
+CONFIG_HID_DRAGONRISE=y
+CONFIG_DRAGONRISE_FF=y
+CONFIG_HID_GYRATION=y
+CONFIG_HID_TWINHAN=y
+CONFIG_LOGITECH_FF=y
+CONFIG_LOGIRUMBLEPAD2_FF=y
+CONFIG_HID_NTRIG=y
+CONFIG_HID_PANTHERLORD=y
+CONFIG_PANTHERLORD_FF=y
+CONFIG_HID_PETALYNX=y
+CONFIG_HID_SAMSUNG=y
+CONFIG_HID_SONY=y
+CONFIG_HID_SUNPLUS=y
+CONFIG_HID_GREENASIA=y
+CONFIG_GREENASIA_FF=y
+CONFIG_HID_SMARTJOYPLUS=y
+CONFIG_SMARTJOYPLUS_FF=y
+CONFIG_HID_TOPSEED=y
+CONFIG_HID_THRUSTMASTER=y
+CONFIG_THRUSTMASTER_FF=y
+CONFIG_HID_ZEROPLUS=y
+CONFIG_ZEROPLUS_FF=y
+CONFIG_USB=y
+# CONFIG_USB_DEVICE_CLASS is not set
+CONFIG_USB_DYNAMIC_MINORS=y
+CONFIG_USB_MON=y
+CONFIG_USB_EHCI_HCD=y
+CONFIG_USB_EHCI_ROOT_HUB_TT=y
+# CONFIG_USB_EHCI_TT_NEWSCHED is not set
+CONFIG_USB_OHCI_HCD=y
+CONFIG_USB_STORAGE=y
+CONFIG_USB_LIBUSUAL=y
+CONFIG_RTC_CLASS=y
+CONFIG_RTC_DRV_CMOS=y
+CONFIG_STAGING=y
+# CONFIG_STAGING_EXCLUDE_BUILD is not set
+CONFIG_FB_SM7XX=y
+CONFIG_EXT4_FS=y
+CONFIG_TMPFS=y
+# CONFIG_MISC_FILESYSTEMS is not set
+# CONFIG_NETWORK_FILESYSTEMS is not set
+CONFIG_NLS_DEFAULT="utf8"
+CONFIG_NLS_ASCII=y
+CONFIG_NLS_UTF8=y
+CONFIG_FRAME_WARN=1024
+CONFIG_STRIP_ASM_SYMS=y
+# CONFIG_RCU_CPU_STALL_DETECTOR is not set
diff --git a/arch/mips/configs/yeeloong_tiny_defconfig b/arch/mips/configs/yeeloong_tiny_defconfig
new file mode 100644
index 0000000..93e3e7b
--- /dev/null
+++ b/arch/mips/configs/yeeloong_tiny_defconfig
@@ -0,0 +1,74 @@
+CONFIG_MACH_LOONGSON=y
+CONFIG_LEMOTE_MACH2F=y
+CONFIG_HZ_1000=y
+CONFIG_PREEMPT=y
+# CONFIG_LOCALVERSION_AUTO is not set
+CONFIG_KERNEL_LZMA=y
+# CONFIG_SWAP is not set
+CONFIG_TINY_RCU=y
+CONFIG_LOG_BUF_SHIFT=15
+CONFIG_EMBEDDED=y
+# CONFIG_KALLSYMS is not set
+# CONFIG_HOTPLUG is not set
+# CONFIG_PRINTK is not set
+# CONFIG_BUG is not set
+# CONFIG_ELF_CORE is not set
+# CONFIG_PCSPKR_PLATFORM is not set
+# CONFIG_BASE_FULL is not set
+# CONFIG_FUTEX is not set
+# CONFIG_EPOLL is not set
+# CONFIG_SIGNALFD is not set
+# CONFIG_TIMERFD is not set
+# CONFIG_EVENTFD is not set
+# CONFIG_SHMEM is not set
+# CONFIG_AIO is not set
+# CONFIG_VM_EVENT_COUNTERS is not set
+# CONFIG_PCI_QUIRKS is not set
+CONFIG_SLOB=y
+# CONFIG_LBDAF is not set
+# CONFIG_BLK_DEV_BSG is not set
+# CONFIG_IOSCHED_DEADLINE is not set
+# CONFIG_IOSCHED_CFQ is not set
+CONFIG_PCI=y
+# CONFIG_FW_LOADER is not set
+# CONFIG_BLK_DEV is not set
+CONFIG_BLK_DEV_SD=y
+# CONFIG_SCSI_LOWLEVEL is not set
+CONFIG_ATA=y
+# CONFIG_ATA_VERBOSE_ERROR is not set
+# CONFIG_SATA_PMP is not set
+CONFIG_PATA_AMD=y
+# CONFIG_INPUT_MOUSEDEV is not set
+# CONFIG_INPUT_MOUSE is not set
+# CONFIG_SERIO_SERPORT is not set
+# CONFIG_CONSOLE_TRANSLATIONS is not set
+# CONFIG_DEVKMEM is not set
+# CONFIG_UNIX98_PTYS is not set
+# CONFIG_LEGACY_PTYS is not set
+# CONFIG_HW_RANDOM is not set
+# CONFIG_HWMON is not set
+# CONFIG_MFD_SUPPORT is not set
+# CONFIG_VGA_ARB is not set
+CONFIG_FB=y
+# CONFIG_VGA_CONSOLE is not set
+CONFIG_FRAMEBUFFER_CONSOLE=y
+# CONFIG_HID_SUPPORT is not set
+# CONFIG_USB_SUPPORT is not set
+CONFIG_RTC_CLASS=y
+CONFIG_RTC_DRV_CMOS=y
+CONFIG_STAGING=y
+# CONFIG_STAGING_EXCLUDE_BUILD is not set
+CONFIG_FB_SM7XX=y
+# CONFIG_MIPS_PLATFORM_DEVICES is not set
+CONFIG_EXT2_FS=y
+# CONFIG_FILE_LOCKING is not set
+# CONFIG_DNOTIFY is not set
+# CONFIG_INOTIFY_USER is not set
+# CONFIG_PROC_FS is not set
+# CONFIG_SYSFS is not set
+# CONFIG_MISC_FILESYSTEMS is not set
+# CONFIG_ENABLE_WARN_DEPRECATED is not set
+# CONFIG_ENABLE_MUST_CHECK is not set
+CONFIG_STRIP_ASM_SYMS=y
+# CONFIG_BKL is not set
+CONFIG_CRC16=y
diff --git a/arch/mips/include/asm/clock.h b/arch/mips/include/asm/clock.h
deleted file mode 100644
index 83894aa..0000000
--- a/arch/mips/include/asm/clock.h
+++ /dev/null
@@ -1,64 +0,0 @@
-#ifndef __ASM_MIPS_CLOCK_H
-#define __ASM_MIPS_CLOCK_H
-
-#include <linux/kref.h>
-#include <linux/list.h>
-#include <linux/seq_file.h>
-#include <linux/clk.h>
-
-extern void (*cpu_wait) (void);
-
-struct clk;
-
-struct clk_ops {
- void (*init) (struct clk *clk);
- void (*enable) (struct clk *clk);
- void (*disable) (struct clk *clk);
- void (*recalc) (struct clk *clk);
- int (*set_rate) (struct clk *clk, unsigned long rate, int algo_id);
- long (*round_rate) (struct clk *clk, unsigned long rate);
-};
-
-struct clk {
- struct list_head node;
- const char *name;
- int id;
- struct module *owner;
-
- struct clk *parent;
- struct clk_ops *ops;
-
- struct kref kref;
-
- unsigned long rate;
- unsigned long flags;
-};
-
-#define CLK_ALWAYS_ENABLED (1 << 0)
-#define CLK_RATE_PROPAGATES (1 << 1)
-
-/* Should be defined by processor-specific code */
-void arch_init_clk_ops(struct clk_ops **, int type);
-
-int clk_init(void);
-
-int __clk_enable(struct clk *);
-void __clk_disable(struct clk *);
-
-void clk_recalc_rate(struct clk *);
-
-int clk_register(struct clk *);
-void clk_unregister(struct clk *);
-
-/* the exported API, in addition to clk_set_rate */
-/**
- * clk_set_rate_ex - set the clock rate for a clock source, with additional parameter
- * @clk: clock source
- * @rate: desired clock rate in Hz
- * @algo_id: algorithm id to be passed down to ops->set_rate
- *
- * Returns success (0) or negative errno.
- */
-int clk_set_rate_ex(struct clk *clk, unsigned long rate, int algo_id);
-
-#endif /* __ASM_MIPS_CLOCK_H */
diff --git a/arch/mips/include/asm/cpu-features.h b/arch/mips/include/asm/cpu-features.h
index ca400f7..c4e1834 100644
--- a/arch/mips/include/asm/cpu-features.h
+++ b/arch/mips/include/asm/cpu-features.h
@@ -13,8 +13,12 @@
#include <asm/cpu-info.h>
#include <cpu-feature-overrides.h>
+#ifndef current_cpu_prid
+#define current_cpu_prid() current_cpu_data.processor_id
+#endif
+
#ifndef current_cpu_type
-#define current_cpu_type() current_cpu_data.cputype
+#define current_cpu_type() current_cpu_data.cputype
#endif
/*
diff --git a/arch/mips/include/asm/cpu.h b/arch/mips/include/asm/cpu.h
index 5f95a4b..9b29ae7 100644
--- a/arch/mips/include/asm/cpu.h
+++ b/arch/mips/include/asm/cpu.h
@@ -37,6 +37,8 @@
#define PRID_COMP_CAVIUM 0x0d0000
#define PRID_COMP_INGENIC 0xd00000
+#define PRID_COMP_MASK 0xff0000
+
/*
* Assigned values for the product ID register. In order to detect a
* certain CPU type exactly eventually additional registers may need to
@@ -74,6 +76,7 @@
#define PRID_IMP_LOONGSON2 0x6300
#define PRID_IMP_UNKNOWN 0xff00
+#define PRID_IMP_MASK 0xff00
/*
* These are the PRID's for when 23:16 == PRID_COMP_MIPS
@@ -192,6 +195,12 @@
#define PRID_REV_LOONGSON2E 0x0002
#define PRID_REV_LOONGSON2F 0x0003
+#define cpu_prid_comp() (current_cpu_prid() & PRID_COMP_MASK)
+#define cpu_prid_imp() (current_cpu_prid() & PRID_IMP_MASK)
+#define cpu_prid_rev() (current_cpu_prid() & PRID_REV_MASK)
+
+#define cpu_prid_encode(comp, imp, rev) ((comp) | (imp) | (rev))
+
/*
* Older processors used to encode processor version and revision in two
* 4-bit bitfields, the 4K seems to simply count up and even newer MTI cores
@@ -321,5 +330,4 @@
#define MIPS_ASE_DSP 0x00000010 /* Signal Processing ASE */
#define MIPS_ASE_MIPSMT 0x00000020 /* CPU supports MIPS MT */
-
#endif /* _ASM_CPU_H */
diff --git a/arch/mips/include/asm/dma-mapping.h b/arch/mips/include/asm/dma-mapping.h
index 7aa37dd..655f849 100644
--- a/arch/mips/include/asm/dma-mapping.h
+++ b/arch/mips/include/asm/dma-mapping.h
@@ -5,9 +5,7 @@
#include <asm/cache.h>
#include <asm-generic/dma-coherent.h>
-#ifndef CONFIG_SGI_IP27 /* Kludge to fix 2.6.39 build for IP27 */
#include <dma-coherence.h>
-#endif
extern struct dma_map_ops *mips_dma_map_ops;
diff --git a/arch/mips/include/asm/ftrace.h b/arch/mips/include/asm/ftrace.h
index ce35c9a..4c02d4c 100644
--- a/arch/mips/include/asm/ftrace.h
+++ b/arch/mips/include/asm/ftrace.h
@@ -3,7 +3,7 @@
* License. See the file "COPYING" in the main directory of this archive for
* more details.
*
- * Copyright (C) 2009 DSLab, Lanzhou University, China
+ * Copyright (C) 2009, 2010 DSLab, Lanzhou University, China
* Author: Wu Zhangjin <wuzhangjin@gmail.com>
*/
@@ -83,8 +83,8 @@
struct dyn_arch_ftrace {
};
-
#endif /* CONFIG_DYNAMIC_FTRACE */
+
#endif /* __ASSEMBLY__ */
#endif /* CONFIG_FUNCTION_TRACER */
#endif /* _ASM_MIPS_FTRACE_H */
diff --git a/arch/mips/include/asm/inst.h b/arch/mips/include/asm/inst.h
index 7ebfc39..0e8ba7c 100644
--- a/arch/mips/include/asm/inst.h
+++ b/arch/mips/include/asm/inst.h
@@ -61,6 +61,8 @@
enum spec2_op {
madd_op, maddu_op, mul_op, spec2_3_unused_op,
msub_op, msubu_op, /* more unused ops */
+ loongson_madd_op = 0x18, loongson_msub_op,
+ loongson_nmadd_op, loongson_nmsub_op,
clz_op = 0x20, clo_op,
dclz_op = 0x24, dclo_op,
sdbpp_op = 0x3f
@@ -133,7 +135,7 @@
*/
enum cop1_fmt {
s_fmt, d_fmt, e_fmt, q_fmt,
- w_fmt, l_fmt
+ w_fmt, l_fmt, ps_fmt
};
/*
@@ -161,8 +163,8 @@
*/
enum cop1x_func {
lwxc1_op = 0x00, ldxc1_op = 0x01,
- pfetch_op = 0x07, swxc1_op = 0x08,
- sdxc1_op = 0x09, madd_s_op = 0x20,
+ swxc1_op = 0x08, sdxc1_op = 0x09,
+ prefx_op = 0x17, madd_s_op = 0x20,
madd_d_op = 0x21, madd_e_op = 0x22,
msub_s_op = 0x28, msub_d_op = 0x29,
msub_e_op = 0x2a, nmadd_s_op = 0x30,
@@ -251,7 +253,7 @@
unsigned int func : 6;
};
-struct ma_format { /* FPU multipy and add format (MIPS IV) */
+struct ma_format { /* FPU multiply and add format (MIPS IV) */
unsigned int opcode : 6;
unsigned int fr : 5;
unsigned int ft : 5;
@@ -324,7 +326,7 @@
unsigned int opcode : 6;
};
-struct ma_format { /* FPU multipy and add format (MIPS IV) */
+struct ma_format { /* FPU multiply and add format (MIPS IV) */
unsigned int fmt : 2;
unsigned int func : 4;
unsigned int fd : 5;
diff --git a/arch/mips/include/asm/mach-loongson/cpu-feature-overrides.h b/arch/mips/include/asm/mach-loongson/cpu-feature-overrides.h
index 675bd86..5938f70 100644
--- a/arch/mips/include/asm/mach-loongson/cpu-feature-overrides.h
+++ b/arch/mips/include/asm/mach-loongson/cpu-feature-overrides.h
@@ -16,6 +16,20 @@
#ifndef __ASM_MACH_LOONGSON_CPU_FEATURE_OVERRIDES_H
#define __ASM_MACH_LOONGSON_CPU_FEATURE_OVERRIDES_H
+#ifdef CONFIG_CPU_LOONGSON2
+#define cpu_prid_loongson2() \
+ cpu_prid_encode(PRID_COMP_LEGACY, PRID_IMP_LOONGSON2, 0)
+
+#ifdef CONFIG_CPU_LOONGSON2F
+#define current_cpu_prid() (cpu_prid_loongson2() | PRID_REV_LOONGSON2F)
+#else /* CONFIG_CPU_LOONGSON2E */
+#define current_cpu_prid() (cpu_prid_loongson2() | PRID_REV_LOONGSON2E)
+#endif
+
+#endif /* CONFIG_CPU_LOONGSON2 */
+
+#define current_cpu_type() CPU_LOONGSON2
+
#define cpu_dcache_line_size() 32
#define cpu_icache_line_size() 32
#define cpu_scache_line_size() 32
diff --git a/arch/mips/include/asm/mach-loongson/cs5536/cs5536.h b/arch/mips/include/asm/mach-loongson/cs5536/cs5536.h
index 2a8e2bb..38bceee 100644
--- a/arch/mips/include/asm/mach-loongson/cs5536/cs5536.h
+++ b/arch/mips/include/asm/mach-loongson/cs5536/cs5536.h
@@ -255,21 +255,12 @@
* IDE STANDARD
*/
#define IDE_CAP 0x00
-#define IDE_CONFIG 0x01
-#define IDE_SMI 0x02
-#define IDE_ERROR 0x03
-#define IDE_PM 0x04
-#define IDE_DIAG 0x05
-
-/*
- * IDE SPEC.
- */
#define IDE_IO_BAR 0x08
#define IDE_CFG 0x10
#define IDE_DTC 0x12
#define IDE_CAST 0x13
#define IDE_ETC 0x14
-#define IDE_INTERNAL_PM 0x15
+#define IDE_PM 0x15
/*
* ACC STANDARD
@@ -301,5 +292,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 --git a/arch/mips/include/asm/mach-loongson/cs5536/cs5536_mfgpt.h b/arch/mips/include/asm/mach-loongson/cs5536/cs5536_mfgpt.h
index 4b493d6..d058e46 100644
--- a/arch/mips/include/asm/mach-loongson/cs5536/cs5536_mfgpt.h
+++ b/arch/mips/include/asm/mach-loongson/cs5536/cs5536_mfgpt.h
@@ -10,26 +10,45 @@
#ifdef CONFIG_CS5536_MFGPT
extern void setup_mfgpt0_timer(void);
-extern void disable_mfgpt0_counter(void);
-extern void enable_mfgpt0_counter(void);
+extern void disable_mfgpt_counter(void);
+extern void enable_mfgpt_counter(void);
#else
static inline void __maybe_unused setup_mfgpt0_timer(void)
{
}
-static inline void __maybe_unused disable_mfgpt0_counter(void)
+static inline void __maybe_unused disable_mfgpt_counter(void)
{
}
-static inline void __maybe_unused enable_mfgpt0_counter(void)
+static inline void __maybe_unused enable_mfgpt_counter(void)
{
}
#endif
-#define MFGPT_TICK_RATE 14318000
-#define COMPARE ((MFGPT_TICK_RATE + HZ/2) / HZ)
+#define MFGPT_CLK_RATE(c) ((14318000UL-32768)*c + 32768)
+#define MFGPT_TICK_RATE(c, scale) (MFGPT_CLK_RATE(c) / (1 << scale))
+#define MFGPT_COMPARE(c, scale) ((MFGPT_TICK_RATE(c, scale)+HZ/2)/HZ)
-#define MFGPT_BASE mfgpt_base
-#define MFGPT0_CMP2 (MFGPT_BASE + 2)
-#define MFGPT0_CNT (MFGPT_BASE + 4)
-#define MFGPT0_SETUP (MFGPT_BASE + 6)
+#define MFGPT_SETUP_ENABLE (1 << 15)
+#define MFGPT_SETUP_ACK (3 << 13)
+#define MFGPT_SETUP_SETUP (1 << 12)
+#define MFGPT_SETUP_CMP2EVT (3 << 8)
+#define MFGPT_SETUP_CMP1EVT (3 << 6)
+#define MFGPT_SETUP_CLOCK(c) (c << 4)
+#define MFGPT_SETUP_SCALE(scale) scale
+
+#define MFGPT0_CMP1 mfgpt_base
+#define MFGPT0_CMP2 (mfgpt_base + 0x02)
+#define MFGPT0_CNT (mfgpt_base + 0x04)
+#define MFGPT0_SETUP (mfgpt_base + 0x06)
+
+#define MFGPT1_CMP1 (mfgpt_base + 0x08)
+#define MFGPT1_CMP2 (mfgpt_base + 0x0A)
+#define MFGPT1_CNT (mfgpt_base + 0x0C)
+#define MFGPT1_SETUP (mfgpt_base + 0x0E)
+
+#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 --git a/arch/mips/include/asm/mach-loongson/cs5536/cs5536_pci.h b/arch/mips/include/asm/mach-loongson/cs5536/cs5536_pci.h
index 0dca9c8..cfefc37 100644
--- a/arch/mips/include/asm/mach-loongson/cs5536/cs5536_pci.h
+++ b/arch/mips/include/asm/mach-loongson/cs5536/cs5536_pci.h
@@ -13,6 +13,7 @@
#include <linux/types.h>
#include <linux/pci_regs.h>
+#include <linux/pci_ids.h>
extern void cs5536_pci_conf_write4(int function, int reg, u32 value);
extern u32 cs5536_pci_conf_read4(int function, int reg);
@@ -44,16 +45,6 @@
#define CFG_PCI_VENDOR_ID(mod_dev_id, sys_vendor_id) \
(((mod_dev_id) << 16) | (sys_vendor_id))
-/* VENDOR ID */
-#define CS5536_VENDOR_ID 0x1022
-
-/* DEVICE ID */
-#define CS5536_ISA_DEVICE_ID 0x2090
-#define CS5536_IDE_DEVICE_ID 0x209a
-#define CS5536_ACC_DEVICE_ID 0x2093
-#define CS5536_OHCI_DEVICE_ID 0x2094
-#define CS5536_EHCI_DEVICE_ID 0x2095
-
/* CLASS CODE : CLASS SUB-CLASS INTERFACE */
#define CS5536_ISA_CLASS_CODE 0x060100
#define CS5536_IDE_CLASS_CODE 0x010180
@@ -86,16 +77,6 @@
/* CARDBUS CIS POINTER */
#define PCI_CARDBUS_CIS_POINTER 0x00000000
-/* SUBSYSTEM VENDOR ID */
-#define CS5536_SUB_VENDOR_ID CS5536_VENDOR_ID
-
-/* SUBSYSTEM ID */
-#define CS5536_ISA_SUB_ID CS5536_ISA_DEVICE_ID
-#define CS5536_IDE_SUB_ID CS5536_IDE_DEVICE_ID
-#define CS5536_ACC_SUB_ID CS5536_ACC_DEVICE_ID
-#define CS5536_OHCI_SUB_ID CS5536_OHCI_DEVICE_ID
-#define CS5536_EHCI_SUB_ID CS5536_EHCI_DEVICE_ID
-
/* EXPANSION ROM BAR */
#define PCI_EXPANSION_ROM_BAR 0x00000000
diff --git a/arch/mips/include/asm/mach-loongson/cs5536/cs5536_vsm.h b/arch/mips/include/asm/mach-loongson/cs5536/cs5536_vsm.h
index 21c4ece..40f6a81 100644
--- a/arch/mips/include/asm/mach-loongson/cs5536/cs5536_vsm.h
+++ b/arch/mips/include/asm/mach-loongson/cs5536/cs5536_vsm.h
@@ -17,15 +17,43 @@
extern void pci_##name##_write_reg(int reg, u32 value); \
extern u32 pci_##name##_read_reg(int reg);
-/* ide module */
-DECLARE_CS5536_MODULE(ide)
-/* acc module */
-DECLARE_CS5536_MODULE(acc)
-/* ohci module */
-DECLARE_CS5536_MODULE(ohci)
+#define DEFINE_CS5536_MODULE(name) \
+static void pci_##name##_write_reg(int reg, u32 value) {} \
+static u32 pci_##name##_read_reg(int reg) { return 0; }
+
/* isa module */
+#ifdef CONFIG_CS5536_ISA
DECLARE_CS5536_MODULE(isa)
+#else
+DEFINE_CS5536_MODULE(isa)
+#endif
+
+/* ide module */
+#ifdef CONFIG_CS5536_IDE
+DECLARE_CS5536_MODULE(ide)
+#else
+DEFINE_CS5536_MODULE(ide)
+#endif
+
+/* acc module */
+#ifdef CONFIG_CS5536_AUDIO
+DECLARE_CS5536_MODULE(acc)
+#else
+DEFINE_CS5536_MODULE(acc)
+#endif
+
+/* ohci module */
+#ifdef CONFIG_CS5536_OHCI
+DECLARE_CS5536_MODULE(ohci)
+#else
+DEFINE_CS5536_MODULE(ohci)
+#endif
+
/* ehci module */
+#ifdef CONFIG_CS5536_EHCI
DECLARE_CS5536_MODULE(ehci)
+#else
+DEFINE_CS5536_MODULE(ehci)
+#endif
#endif /* _CS5536_VSM_H */
diff --git a/arch/mips/loongson/lemote-2f/ec_kb3310b.h b/arch/mips/include/asm/mach-loongson/ec_kb3310b.h
similarity index 80%
rename from arch/mips/loongson/lemote-2f/ec_kb3310b.h
rename to arch/mips/include/asm/mach-loongson/ec_kb3310b.h
index 1595a21..2e86905 100644
--- a/arch/mips/loongson/lemote-2f/ec_kb3310b.h
+++ b/arch/mips/include/asm/mach-loongson/ec_kb3310b.h
@@ -3,6 +3,8 @@
*
* 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
@@ -22,6 +24,9 @@
typedef int (*sci_handler) (int status);
extern sci_handler yeeloong_report_lid_status;
+#define ON 1
+#define OFF 0
+
#define SCI_IRQ_NUM 0x0A
/*
@@ -53,24 +58,20 @@
#define CMD_GET_EVENT_NUM 0x84
#define CMD_PROGRAM_PIECE 0xda
-/* temperature & fan registers */
+/* 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 */
+/* Fan speed divider */
#define FAN_SPEED_DIVIDER 480000 /* (60*1000*1000/62.5/2)*/
-/* battery registers */
+/* Battery registers */
#define REG_BAT_DESIGN_CAP_HIGH 0xF77D
#define REG_BAT_DESIGN_CAP_LOW 0xF77E
#define REG_BAT_FULLCHG_CAP_HIGH 0xF780
@@ -104,14 +105,11 @@
#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
@@ -120,28 +118,16 @@
#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)
@@ -155,34 +141,30 @@
#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_LID = 0x23, /* Turn on/off LID */
+ EVENT_SWITCHVIDEOMODE, /* 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_DISPLAYTOGGLE, /* Fn+F2, Turn on/off backlight */
+ EVENT_AUDIO_MUTE, /* Fn+F4, Mute on/off */
+ EVENT_DISPLAY_BRIGHTNESS,/* Fn+^/V, LCD backlight brightness adjust */
EVENT_AC_BAT, /* AC & Battery relative issue */
- EVENT_AUDIO_VOLUME, /* Volume adjust */
+ EVENT_AUDIO_VOLUME, /* Fn+<|>, Volume adjust */
EVENT_WLAN, /* Wlan on/off */
- EVENT_END
};
+#define EVENT_START EVENT_LID
+#define EVENT_END EVENT_WLAN
+
#endif /* !_EC_KB3310B_H */
diff --git a/arch/mips/include/asm/mach-loongson/gpio.h b/arch/mips/include/asm/mach-loongson/gpio.h
index e30e73d..0fd06bf 100644
--- a/arch/mips/include/asm/mach-loongson/gpio.h
+++ b/arch/mips/include/asm/mach-loongson/gpio.h
@@ -13,12 +13,16 @@
#ifndef __STLS2F_GPIO_H
#define __STLS2F_GPIO_H
+#ifdef CONFIG_GENERIC_GPIO
+#define ARCH_NR_GPIOS 4
#include <asm-generic/gpio.h>
extern void gpio_set_value(unsigned gpio, int value);
extern int gpio_get_value(unsigned gpio);
extern int gpio_cansleep(unsigned gpio);
+#endif
+
/* The chip can do interrupt
* but it has not been tested and doc not clear
*/
diff --git a/arch/mips/include/asm/mach-loongson/loongson.h b/arch/mips/include/asm/mach-loongson/loongson.h
index 1e29b9d..ed089c7 100644
--- a/arch/mips/include/asm/mach-loongson/loongson.h
+++ b/arch/mips/include/asm/mach-loongson/loongson.h
@@ -31,17 +31,13 @@
extern void __init prom_init_cmdline(void);
extern void __init prom_init_machtype(void);
extern void __init prom_init_env(void);
-#ifdef CONFIG_LOONGSON_UART_BASE
-extern unsigned long _loongson_uart_base, loongson_uart_base;
-extern void prom_init_loongson_uart_base(void);
-#endif
+extern void __init prom_init_uart_base(void);
-static inline void prom_init_uart_base(void)
-{
-#ifdef CONFIG_LOONGSON_UART_BASE
- prom_init_loongson_uart_base();
-#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);
@@ -243,12 +239,14 @@
((((ADDR)>>26) & LOONGSON_PCIMAP_PCIMAP_LO0) << ((WIN)*6))
#ifdef CONFIG_CPU_SUPPORTS_CPUFREQ
-#include <linux/cpufreq.h>
-extern void loongson2_cpu_wait(void);
-extern struct cpufreq_frequency_table loongson2_clockmod_table[];
-
/* Chip Config */
#define LOONGSON_CHIPCFG0 LOONGSON_REG(LOONGSON_REGBASE + 0x80)
+#define LOONGSON_GET_CPUFREQ() (LOONGSON_CHIPCFG0 & 7)
+
+#define LOONGSON_SET_CPUFREQ(level) do { \
+ LOONGSON_CHIPCFG0 = (LOONGSON_CHIPCFG0 & (~7)) | (level); \
+} while (0)
+
#endif
/*
diff --git a/arch/mips/include/asm/mach-loongson/machine.h b/arch/mips/include/asm/mach-loongson/machine.h
index 4321338..8575995 100644
--- a/arch/mips/include/asm/mach-loongson/machine.h
+++ b/arch/mips/include/asm/mach-loongson/machine.h
@@ -12,16 +12,16 @@
#define __ASM_MACH_LOONGSON_MACHINE_H
#ifdef CONFIG_LEMOTE_FULOONG2E
-
-#define LOONGSON_MACHTYPE MACH_LEMOTE_FL2E
-
+ #define LOONGSON_MACHTYPE MACH_LEMOTE_FL2E
#endif
/* use fuloong2f as the default machine of LEMOTE_MACH2F */
#ifdef CONFIG_LEMOTE_MACH2F
+ #define LOONGSON_MACHTYPE MACH_LEMOTE_FL2F
+#endif
-#define LOONGSON_MACHTYPE MACH_LEMOTE_FL2F
-
+#ifdef CONFIG_DEXXON_GDIUM
+ #define LOONGSON_MACHTYPE MACH_DEXXON_GDIUM2F10
#endif
#endif /* __ASM_MACH_LOONGSON_MACHINE_H */
diff --git a/arch/mips/include/asm/timex.h b/arch/mips/include/asm/timex.h
index 6529704..bf6a701 100644
--- a/arch/mips/include/asm/timex.h
+++ b/arch/mips/include/asm/timex.h
@@ -10,6 +10,10 @@
#ifdef __KERNEL__
+#ifdef CONFIG_CSRC_R4K
+#define ARCH_HAS_PREPARED_LPJ
+#endif
+
#include <asm/mipsregs.h>
/*
diff --git a/arch/mips/kernel/cevt-r4k.c b/arch/mips/kernel/cevt-r4k.c
index 98c5a97..0f33eba 100644
--- a/arch/mips/kernel/cevt-r4k.c
+++ b/arch/mips/kernel/cevt-r4k.c
@@ -11,6 +11,7 @@
#include <linux/percpu.h>
#include <linux/smp.h>
#include <linux/irq.h>
+#include <linux/module.h>
#include <asm/smtc_ipi.h>
#include <asm/time.h>
@@ -23,6 +24,51 @@
#ifndef CONFIG_MIPS_MT_SMTC
+#ifdef CONFIG_R4K_TIMER_FOR_CPUFREQ
+
+extern cycle_t read_virtual_count(void);
+extern unsigned int scale_shift;
+#define hpt_scale_down(cycle) ((cycle) >> scale_shift)
+#define hpt_scale_down_shift(cycle, shift) ((cycle) >> (shift))
+
+static u64 last_hpt_target;
+
+static inline void update_virtual_target(u32 delta)
+{
+ last_hpt_target = read_virtual_count() + delta;
+}
+
+/*
+ * This should be called with irq disabled and spin lock
+ *
+ * We must update the virtual clocksource and the clockevent when prepare or
+ * post change the cpu frequency.
+ */
+
+void notrace update_virtual_count(unsigned int target_scale_shift)
+{
+ u64 now64;
+ /*
+ * If we want to change the cpufreq before the target timer event is
+ * met, we must update the delta to the new one.
+ */
+ now64 = read_virtual_count();
+ if (now64 < last_hpt_target) {
+ unsigned int cnt = read_c0_count();
+ cnt += hpt_scale_down_shift((last_hpt_target - now64),
+ target_scale_shift);
+ write_c0_compare(cnt);
+ }
+}
+EXPORT_SYMBOL(update_virtual_count);
+
+#else
+
+#define hpt_scale_down(cycle) (cycle)
+#define update_virtual_target(delta)
+
+#endif /* CONFIG_R4K_TIMER_FOR_CPUFREQ */
+
static int mips_next_event(unsigned long delta,
struct clock_event_device *evt)
{
@@ -30,9 +76,13 @@
int res;
cnt = read_c0_count();
- cnt += delta;
+ cnt += hpt_scale_down(delta);
write_c0_compare(cnt);
res = ((int)(read_c0_count() - cnt) >= 0) ? -ETIME : 0;
+
+ /* Update the virtual counter */
+ update_virtual_target(delta);
+
return res;
}
diff --git a/arch/mips/kernel/cpu-probe.c b/arch/mips/kernel/cpu-probe.c
index ebc0cd2..8a0a407 100644
--- a/arch/mips/kernel/cpu-probe.c
+++ b/arch/mips/kernel/cpu-probe.c
@@ -152,14 +152,12 @@
void __init check_wait(void)
{
- struct cpuinfo_mips *c = ¤t_cpu_data;
-
if (nowait) {
printk("Wait instruction disabled.\n");
return;
}
- switch (c->cputype) {
+ switch (current_cpu_type()) {
case CPU_R3081:
case CPU_R3081E:
cpu_wait = r3081_wait;
@@ -207,7 +205,7 @@
case CPU_74K:
cpu_wait = r4k_wait;
- if ((c->processor_id & 0xff) >= PRID_REV_ENCODE_332(2, 1, 0))
+ if (cpu_prid_rev() >= PRID_REV_ENCODE_332(2, 1, 0))
cpu_wait = r4k_wait_irqoff;
break;
@@ -223,7 +221,7 @@
* WAIT on Rev2.0 and Rev3.0 has E16.
* Rev3.1 WAIT is nop, why bother
*/
- if ((c->processor_id & 0xff) <= 0x64)
+ if (cpu_prid_rev() <= 0x64)
break;
/*
@@ -236,7 +234,7 @@
*/
break;
case CPU_RM9000:
- if ((c->processor_id & 0x00ff) >= 0x40)
+ if (cpu_prid_rev() >= 0x40)
cpu_wait = r4k_wait;
break;
default:
@@ -246,16 +244,14 @@
static inline void check_errata(void)
{
- struct cpuinfo_mips *c = ¤t_cpu_data;
-
- switch (c->cputype) {
+ switch (current_cpu_type()) {
case CPU_34K:
/*
* Erratum "RPS May Cause Incorrect Instruction Execution"
* This code only handles VPE0, any SMP/SMTC/RTOS code
* making use of VPE1 will be responsable for that VPE.
*/
- if ((c->processor_id & PRID_REV_MASK) <= PRID_REV_34K_V1_0_2)
+ if (cpu_prid_rev() <= PRID_REV_34K_V1_0_2)
write_c0_config7(read_c0_config7() | MIPS_CONF7_RPS);
break;
default:
@@ -332,7 +328,7 @@
static inline void cpu_probe_legacy(struct cpuinfo_mips *c, unsigned int cpu)
{
- switch (c->processor_id & 0xff00) {
+ switch (cpu_prid_imp()) {
case PRID_IMP_R2000:
c->cputype = CPU_R2000;
__cpu_name[cpu] = "R2000";
@@ -344,7 +340,7 @@
c->tlbsize = 64;
break;
case PRID_IMP_R3000:
- if ((c->processor_id & 0xff) == PRID_REV_R3000A) {
+ if (cpu_prid_rev() == PRID_REV_R3000A) {
if (cpu_has_confreg()) {
c->cputype = CPU_R3081E;
__cpu_name[cpu] = "R3081";
@@ -366,7 +362,7 @@
break;
case PRID_IMP_R4000:
if (read_c0_config() & CONF_SC) {
- if ((c->processor_id & 0xff) >= PRID_REV_R4400) {
+ if (cpu_prid_rev() >= PRID_REV_R4400) {
c->cputype = CPU_R4400PC;
__cpu_name[cpu] = "R4400PC";
} else {
@@ -374,7 +370,7 @@
__cpu_name[cpu] = "R4000PC";
}
} else {
- if ((c->processor_id & 0xff) >= PRID_REV_R4400) {
+ if (cpu_prid_rev() >= PRID_REV_R4400) {
c->cputype = CPU_R4400SC;
__cpu_name[cpu] = "R4400SC";
} else {
@@ -390,7 +386,7 @@
c->tlbsize = 48;
break;
case PRID_IMP_VR41XX:
- switch (c->processor_id & 0xf0) {
+ switch (current_cpu_prid() & 0xf0) {
case PRID_REV_VR4111:
c->cputype = CPU_VR4111;
__cpu_name[cpu] = "NEC VR4111";
@@ -400,7 +396,7 @@
__cpu_name[cpu] = "NEC VR4121";
break;
case PRID_REV_VR4122:
- if ((c->processor_id & 0xf) < 0x3) {
+ if ((current_cpu_prid() & 0xf) < 0x3) {
c->cputype = CPU_VR4122;
__cpu_name[cpu] = "NEC VR4122";
} else {
@@ -409,7 +405,7 @@
}
break;
case PRID_REV_VR4130:
- if ((c->processor_id & 0xf) < 0x4) {
+ if ((current_cpu_prid() & 0xf) < 0x4) {
c->cputype = CPU_VR4131;
__cpu_name[cpu] = "NEC VR4131";
} else {
@@ -462,12 +458,12 @@
c->isa_level = MIPS_CPU_ISA_I;
c->options = MIPS_CPU_TLB | MIPS_CPU_TX39_CACHE;
- if ((c->processor_id & 0xf0) == (PRID_REV_TX3927 & 0xf0)) {
+ if ((current_cpu_prid() & 0xf0) == (PRID_REV_TX3927 & 0xf0)) {
c->cputype = CPU_TX3927;
__cpu_name[cpu] = "TX3927";
c->tlbsize = 64;
} else {
- switch (c->processor_id & 0xff) {
+ switch (cpu_prid_rev()) {
case PRID_REV_TX3912:
c->cputype = CPU_TX3912;
__cpu_name[cpu] = "TX3912";
@@ -494,7 +490,7 @@
__cpu_name[cpu] = "R49XX";
c->isa_level = MIPS_CPU_ISA_III;
c->options = R4K_OPTS | MIPS_CPU_LLSC;
- if (!(c->processor_id & 0x08))
+ if (!(current_cpu_prid() & 0x08))
c->options |= MIPS_CPU_FPU | MIPS_CPU_32FPR;
c->tlbsize = 48;
break;
@@ -789,7 +785,7 @@
static inline void cpu_probe_mips(struct cpuinfo_mips *c, unsigned int cpu)
{
decode_configs(c);
- switch (c->processor_id & 0xff00) {
+ switch (cpu_prid_imp()) {
case PRID_IMP_4KC:
c->cputype = CPU_4KC;
__cpu_name[cpu] = "MIPS 4Kc";
@@ -841,11 +837,11 @@
static inline void cpu_probe_alchemy(struct cpuinfo_mips *c, unsigned int cpu)
{
decode_configs(c);
- switch (c->processor_id & 0xff00) {
+ switch (cpu_prid_imp()) {
case PRID_IMP_AU1_REV1:
case PRID_IMP_AU1_REV2:
c->cputype = CPU_ALCHEMY;
- switch ((c->processor_id >> 24) & 0xff) {
+ switch ((current_cpu_prid() >> 24) & 0xff) {
case 0:
__cpu_name[cpu] = "Au1000";
break;
@@ -860,7 +856,7 @@
break;
case 4:
__cpu_name[cpu] = "Au1200";
- if ((c->processor_id & 0xff) == 2)
+ if (cpu_prid_rev() == 2)
__cpu_name[cpu] = "Au1250";
break;
case 5:
@@ -878,12 +874,12 @@
{
decode_configs(c);
- switch (c->processor_id & 0xff00) {
+ switch (cpu_prid_imp()) {
case PRID_IMP_SB1:
c->cputype = CPU_SB1;
__cpu_name[cpu] = "SiByte SB1";
/* FPU in pass1 is known to have issues. */
- if ((c->processor_id & 0xff) < 0x02)
+ if (cpu_prid_rev() < 0x02)
c->options &= ~(MIPS_CPU_FPU | MIPS_CPU_32FPR);
break;
case PRID_IMP_SB1A:
@@ -896,7 +892,7 @@
static inline void cpu_probe_sandcraft(struct cpuinfo_mips *c, unsigned int cpu)
{
decode_configs(c);
- switch (c->processor_id & 0xff00) {
+ switch (cpu_prid_imp()) {
case PRID_IMP_SR71000:
c->cputype = CPU_SR71000;
__cpu_name[cpu] = "Sandcraft SR71000";
@@ -909,7 +905,7 @@
static inline void cpu_probe_nxp(struct cpuinfo_mips *c, unsigned int cpu)
{
decode_configs(c);
- switch (c->processor_id & 0xff00) {
+ switch (cpu_prid_imp()) {
case PRID_IMP_PR4450:
c->cputype = CPU_PR4450;
__cpu_name[cpu] = "Philips PR4450";
@@ -921,7 +917,7 @@
static inline void cpu_probe_broadcom(struct cpuinfo_mips *c, unsigned int cpu)
{
decode_configs(c);
- switch (c->processor_id & 0xff00) {
+ switch (cpu_prid_imp()) {
case PRID_IMP_BMIPS32_REV4:
case PRID_IMP_BMIPS32_REV8:
c->cputype = CPU_BMIPS32;
@@ -936,7 +932,7 @@
set_elf_platform(cpu, "bmips3300");
break;
case PRID_IMP_BMIPS43XX: {
- int rev = c->processor_id & 0xff;
+ int rev = cpu_prid_rev();
if (rev >= PRID_REV_BMIPS4380_LO &&
rev <= PRID_REV_BMIPS4380_HI) {
@@ -962,7 +958,7 @@
static inline void cpu_probe_cavium(struct cpuinfo_mips *c, unsigned int cpu)
{
decode_configs(c);
- switch (c->processor_id & 0xff00) {
+ switch (cpu_prid_imp()) {
case PRID_IMP_CAVIUM_CN38XX:
case PRID_IMP_CAVIUM_CN31XX:
case PRID_IMP_CAVIUM_CN30XX:
@@ -995,7 +991,7 @@
decode_configs(c);
/* JZRISC does not implement the CP0 counter. */
c->options &= ~MIPS_CPU_COUNTER;
- switch (c->processor_id & 0xff00) {
+ switch (cpu_prid_imp()) {
case PRID_IMP_JZRISC:
c->cputype = CPU_JZRISC;
__cpu_name[cpu] = "Ingenic JZRISC";
@@ -1078,7 +1074,7 @@
c->cputype = CPU_UNKNOWN;
c->processor_id = read_c0_prid();
- switch (c->processor_id & 0xff0000) {
+ switch (cpu_prid_comp()) {
case PRID_COMP_LEGACY:
cpu_probe_legacy(c, cpu);
break;
@@ -1157,7 +1153,7 @@
struct cpuinfo_mips *c = ¤t_cpu_data;
printk(KERN_INFO "CPU revision is: %08x (%s)\n",
- c->processor_id, cpu_name_string());
+ current_cpu_prid(), cpu_name_string());
if (c->options & MIPS_CPU_FPU)
printk(KERN_INFO "FPU revision is: %08x\n", c->fpu_id);
}
diff --git a/arch/mips/kernel/cpufreq/Kconfig b/arch/mips/kernel/cpufreq/Kconfig
index 58c601e..f631087 100644
--- a/arch/mips/kernel/cpufreq/Kconfig
+++ b/arch/mips/kernel/cpufreq/Kconfig
@@ -4,11 +4,36 @@
config MIPS_EXTERNAL_TIMER
bool
+ select TIMER_SUPPORTS_CPUFREQ
+
+config R4K_TIMER_FOR_CPUFREQ
+ bool "Enable R4K Timer for CPUFreq Driver"
+ depends on !PREEMPT_RT
+ depends on CSRC_R4K && CEVT_R4K
+ depends on CPU_LOONGSON2F
+ select TIMER_SUPPORTS_CPUFREQ
+ default n
+ help
+ This option ensures the R4K Timer works normally with the CPUFreq
+ driver. Currently, It is only designed for Loongson2F with specific
+ optimization.
+
+ If no external timer provided by your Loongson2F boards, this is
+ preferrable.
+
+ If unsure, say NO, but for Gdium netbook, Say Yes Please to ensure
+ the netbook is not too hot!
+
+# For PREEMPT_RT need precise time, we must disable TIMER_SUPPORTS_CPUFREQ
+# Exactly, we may need to disable the whole cpu freq support
+config TIMER_SUPPORTS_CPUFREQ
+ bool
+ depends on !PREEMPT_RT
config MIPS_CPUFREQ
bool
default y
- depends on CPU_SUPPORTS_CPUFREQ && MIPS_EXTERNAL_TIMER
+ depends on CPU_SUPPORTS_CPUFREQ && TIMER_SUPPORTS_CPUFREQ
if MIPS_CPUFREQ
diff --git a/arch/mips/kernel/cpufreq/Makefile b/arch/mips/kernel/cpufreq/Makefile
index c3479a43..05a5715 100644
--- a/arch/mips/kernel/cpufreq/Makefile
+++ b/arch/mips/kernel/cpufreq/Makefile
@@ -2,4 +2,4 @@
# Makefile for the Linux/MIPS cpufreq.
#
-obj-$(CONFIG_LOONGSON2_CPUFREQ) += loongson2_cpufreq.o loongson2_clock.o
+obj-$(CONFIG_LOONGSON2_CPUFREQ) += loongson2_cpufreq.o
diff --git a/arch/mips/kernel/cpufreq/loongson2_clock.c b/arch/mips/kernel/cpufreq/loongson2_clock.c
deleted file mode 100644
index cefc6e2..0000000
--- a/arch/mips/kernel/cpufreq/loongson2_clock.c
+++ /dev/null
@@ -1,170 +0,0 @@
-/*
- * Copyright (C) 2006 - 2008 Lemote Inc. & Insititute of Computing Technology
- * Author: Yanhua, yanh@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.
- */
-
-#include <linux/cpufreq.h>
-#include <linux/platform_device.h>
-
-#include <asm/clock.h>
-
-#include <loongson.h>
-
-static LIST_HEAD(clock_list);
-static DEFINE_SPINLOCK(clock_lock);
-static DEFINE_MUTEX(clock_list_sem);
-
-/* Minimum CLK support */
-enum {
- DC_ZERO, DC_25PT = 2, DC_37PT, DC_50PT, DC_62PT, DC_75PT,
- DC_87PT, DC_DISABLE, DC_RESV
-};
-
-struct cpufreq_frequency_table loongson2_clockmod_table[] = {
- {DC_RESV, CPUFREQ_ENTRY_INVALID},
- {DC_ZERO, CPUFREQ_ENTRY_INVALID},
- {DC_25PT, 0},
- {DC_37PT, 0},
- {DC_50PT, 0},
- {DC_62PT, 0},
- {DC_75PT, 0},
- {DC_87PT, 0},
- {DC_DISABLE, 0},
- {DC_RESV, CPUFREQ_TABLE_END},
-};
-EXPORT_SYMBOL_GPL(loongson2_clockmod_table);
-
-static struct clk cpu_clk = {
- .name = "cpu_clk",
- .flags = CLK_ALWAYS_ENABLED | CLK_RATE_PROPAGATES,
- .rate = 800000000,
-};
-
-struct clk *clk_get(struct device *dev, const char *id)
-{
- return &cpu_clk;
-}
-EXPORT_SYMBOL(clk_get);
-
-static void propagate_rate(struct clk *clk)
-{
- struct clk *clkp;
-
- list_for_each_entry(clkp, &clock_list, node) {
- if (likely(clkp->parent != clk))
- continue;
- if (likely(clkp->ops && clkp->ops->recalc))
- clkp->ops->recalc(clkp);
- if (unlikely(clkp->flags & CLK_RATE_PROPAGATES))
- propagate_rate(clkp);
- }
-}
-
-int clk_enable(struct clk *clk)
-{
- return 0;
-}
-EXPORT_SYMBOL(clk_enable);
-
-void clk_disable(struct clk *clk)
-{
-}
-EXPORT_SYMBOL(clk_disable);
-
-unsigned long clk_get_rate(struct clk *clk)
-{
- return (unsigned long)clk->rate;
-}
-EXPORT_SYMBOL(clk_get_rate);
-
-void clk_put(struct clk *clk)
-{
-}
-EXPORT_SYMBOL(clk_put);
-
-int clk_set_rate(struct clk *clk, unsigned long rate)
-{
- return clk_set_rate_ex(clk, rate, 0);
-}
-EXPORT_SYMBOL_GPL(clk_set_rate);
-
-int clk_set_rate_ex(struct clk *clk, unsigned long rate, int algo_id)
-{
- int ret = 0;
- int regval;
- int i;
-
- if (likely(clk->ops && clk->ops->set_rate)) {
- unsigned long flags;
-
- spin_lock_irqsave(&clock_lock, flags);
- ret = clk->ops->set_rate(clk, rate, algo_id);
- spin_unlock_irqrestore(&clock_lock, flags);
- }
-
- if (unlikely(clk->flags & CLK_RATE_PROPAGATES))
- propagate_rate(clk);
-
- for (i = 0; loongson2_clockmod_table[i].frequency != CPUFREQ_TABLE_END;
- i++) {
- if (loongson2_clockmod_table[i].frequency ==
- CPUFREQ_ENTRY_INVALID)
- continue;
- if (rate == loongson2_clockmod_table[i].frequency)
- break;
- }
- if (rate != loongson2_clockmod_table[i].frequency)
- return -ENOTSUPP;
-
- clk->rate = rate;
-
- regval = LOONGSON_CHIPCFG0;
- regval = (regval & ~0x7) | (loongson2_clockmod_table[i].index - 1);
- LOONGSON_CHIPCFG0 = regval;
-
- return ret;
-}
-EXPORT_SYMBOL_GPL(clk_set_rate_ex);
-
-long clk_round_rate(struct clk *clk, unsigned long rate)
-{
- if (likely(clk->ops && clk->ops->round_rate)) {
- unsigned long flags, rounded;
-
- spin_lock_irqsave(&clock_lock, flags);
- rounded = clk->ops->round_rate(clk, rate);
- spin_unlock_irqrestore(&clock_lock, flags);
-
- return rounded;
- }
-
- return rate;
-}
-EXPORT_SYMBOL_GPL(clk_round_rate);
-
-/*
- * This is the simple version of Loongson-2 wait, Maybe we need do this in
- * interrupt disabled content
- */
-
-DEFINE_SPINLOCK(loongson2_wait_lock);
-void loongson2_cpu_wait(void)
-{
- u32 cpu_freq;
- unsigned long flags;
-
- spin_lock_irqsave(&loongson2_wait_lock, flags);
- cpu_freq = LOONGSON_CHIPCFG0;
- LOONGSON_CHIPCFG0 &= ~0x7; /* Put CPU into wait mode */
- LOONGSON_CHIPCFG0 = cpu_freq; /* Restore CPU state */
- spin_unlock_irqrestore(&loongson2_wait_lock, flags);
-}
-EXPORT_SYMBOL_GPL(loongson2_cpu_wait);
-
-MODULE_AUTHOR("Yanhua <yanh@lemote.com>");
-MODULE_DESCRIPTION("cpufreq driver for Loongson 2F");
-MODULE_LICENSE("GPL");
diff --git a/arch/mips/kernel/cpufreq/loongson2_cpufreq.c b/arch/mips/kernel/cpufreq/loongson2_cpufreq.c
index ae5db20..fb480d4 100644
--- a/arch/mips/kernel/cpufreq/loongson2_cpufreq.c
+++ b/arch/mips/kernel/cpufreq/loongson2_cpufreq.c
@@ -1,187 +1,305 @@
/*
- * Cpufreq driver for the loongson-2 processors
+ * Cpufreq driver for the loongson-2 (>= 2F) processors
*
- * The 2E revision of loongson processor not support this feature.
- *
- * Copyright (C) 2006 - 2008 Lemote Inc. & Insititute of Computing Technology
- * Author: Yanhua, yanh@lemote.com
+ * Copyright (C) 2010, 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.
*/
#include <linux/cpufreq.h>
-#include <linux/module.h>
-#include <linux/err.h>
-#include <linux/sched.h> /* set_cpus_allowed() */
#include <linux/delay.h>
+#include <linux/module.h>
#include <linux/platform_device.h>
-#include <asm/clock.h>
-
#include <loongson.h>
-static uint nowait;
+#define DC_RESV 0
-static struct clk *cpuclk;
-
-static void (*saved_cpu_wait) (void);
-
-static int loongson2_cpu_freq_notifier(struct notifier_block *nb,
- unsigned long val, void *data);
-
-static struct notifier_block loongson2_cpufreq_notifier_block = {
- .notifier_call = loongson2_cpu_freq_notifier
+/*
+ * For Loongson's frequency is not high, we set the minimum level as 50% to
+ * avoid spending too much time on freq switching
+ */
+static struct cpufreq_frequency_table clockmod_table[] = {
+ {DC_RESV, CPUFREQ_ENTRY_INVALID},
+ {1, 0},
+ {3, 0},
+ {7, 0},
+ {DC_RESV, CPUFREQ_TABLE_END},
};
-static int loongson2_cpu_freq_notifier(struct notifier_block *nb,
- unsigned long val, void *data)
-{
- if (val == CPUFREQ_POSTCHANGE)
- current_cpu_data.udelay_val = loops_per_jiffy;
+static unsigned int max_cpufreq_khz;
- return 0;
+static inline unsigned int idx_to_freq(unsigned int idx)
+{
+ /*
+ * freq = max_cpufreq_khz * ((index + 1) / total levels)
+ * = (max_cpufreq_khz * (index + 1)) / 8
+ * = (max_cpufreq_khz * (index + 1)) >> 3
+ */
+ return (max_cpufreq_khz * (idx + 1)) >> 3;
}
-static unsigned int loongson2_cpufreq_get(unsigned int cpu)
+static inline unsigned int l2_cpufreq_get(unsigned int cpu)
{
- return clk_get_rate(cpuclk);
+ return idx_to_freq(LOONGSON_GET_CPUFREQ());
+}
+
+static inline unsigned int idx_to_scale_shift(unsigned int newstate)
+{
+
+ /*
+ * newstate the the index of the array clockmod_table, the valid value
+ * is 1, 2, 3.
+ *
+ * The return value is the scale_shift for respective frequency.
+ *
+ * newstate | Freq_scale of CR80 | multiple | scale_shift
+ * 1 | 1 | 8 / (1+1) = 4 | 2
+ * 2 | 3 | 8 / (3+1) = 2 | 1
+ * 3 | 7 | 8 / (7+1) = 1 | 0
+ *
+ * scale_shift = 3 - newstate
+ */
+
+ return 3 - newstate;
+}
+
+#ifdef CONFIG_R4K_TIMER_FOR_CPUFREQ
+extern unsigned int scale_shift;
+extern void update_virtual_count(unsigned int target_scale_shift);
+
+static inline void sync_virtual_count(unsigned int target_scale_shift)
+{
+ update_virtual_count(target_scale_shift);
+ scale_shift = target_scale_shift;
+}
+
+static void notrace l2_cpufreq_set(unsigned int newstate)
+{
+ unsigned long flag;
+ unsigned int target_scale_shift;
+
+ target_scale_shift = idx_to_scale_shift(newstate);
+
+ pr_debug("%s: scale_shift = %d, target_scale_shift = %d, target_set: %d\n",
+ __func__, scale_shift, target_scale_shift,
+ clockmod_table[newstate].index);
+
+ /* For we are UP, Give up the spin lock... */
+ raw_local_irq_save(flag);
+ /* When freq becomes higher ... */
+ if (scale_shift > target_scale_shift)
+ sync_virtual_count(target_scale_shift);
+ /* Set the CR80 register */
+ LOONGSON_SET_CPUFREQ(clockmod_table[newstate].index);
+ /* When freq becomes lower ... */
+ if (scale_shift < target_scale_shift)
+ sync_virtual_count(target_scale_shift);
+ raw_local_irq_restore(flag);
+
+ pr_debug("%s: scale_shift = %d, target_scale_shift = %d, target_set: %d\n",
+ __func__, scale_shift, target_scale_shift,
+ clockmod_table[newstate].index);
}
/*
- * Here we notify other drivers of the proposed change and the final change.
+ * The CPUFreq driver will put the cpu into the lowest level(1), no need to do
+ * it here. If we do it here, some CPUFreq governors will not function well,
+ * so, disable the cpu_wait() completely when the R4K is used.
*/
-static int loongson2_cpufreq_target(struct cpufreq_policy *policy,
- unsigned int target_freq,
- unsigned int relation)
+
+#if 0
+/*
+ * Put CPU into the 1st level, We have no good method to recover the timesplice
+ * in wait mode, so, we only allow the CPU gointo the 1st level, not the ZERO
+ * level.
+ *
+ * To avoid recording the garbage result in the kernel tracing, we don't call
+ * notifiers when FUNCTION_TRACER is enabled.
+ */
+
+void notrace loongson2_cpu_wait(void)
{
- unsigned int cpu = policy->cpu;
- unsigned int newstate = 0;
- cpumask_t cpus_allowed;
+#ifdef CONFIG_FUNCTION_TRACER
+ /* If we are already in the 1st level, stop resetting it. */
+ if (LOONGSON_GET_CPUFREQ() != 1)
+ l2_cpufreq_set(1);
+#else
+ {
struct cpufreq_freqs freqs;
- unsigned int freq;
- if (!cpu_online(cpu))
- return -ENODEV;
+ freqs.old = l2_cpufreq_get(0);
+ freqs.new = idx_to_freq(1);
- cpus_allowed = current->cpus_allowed;
- set_cpus_allowed_ptr(current, cpumask_of(cpu));
+ if (freqs.new == freqs.old)
+ return;
- if (cpufreq_frequency_table_target
- (policy, &loongson2_clockmod_table[0], target_freq, relation,
- &newstate))
+ /* notifiers */
+ freqs.cpu = 0;
+ cpufreq_notify_transition(&freqs, CPUFREQ_PRECHANGE);
+
+ /* setting the cpu frequency as the 1st level */
+ l2_cpufreq_set(1);
+
+ /* notifiers */
+ cpufreq_notify_transition(&freqs, CPUFREQ_POSTCHANGE);
+ }
+#endif
+}
+#else
+#define loongson2_cpu_wait NULL
+#endif
+
+#else /* MIPS_EXTERNAL_TIMER */
+
+static void l2_cpufreq_set(unsigned int newstate)
+{
+ unsigned long flags;
+
+ local_irq_save(flags);
+ LOONGSON_SET_CPUFREQ(clockmod_table[newstate].index);
+ local_irq_restore(flags);
+}
+
+static void notrace loongson2_cpu_wait(void)
+{
+ u32 cpufreq;
+ ktime_t kt1, kt2;
+ s64 idle_time_ns;
+ unsigned long flags;
+
+ local_irq_save(flags);
+ kt1 = ktime_get_real();
+ sched_clock_idle_sleep_event();
+
+ /* Record the cpu frequency */
+ cpufreq = LOONGSON_CHIPCFG0;
+
+ /*
+ * Currently, there is no wait instruction in Loongson platform,
+ * herein, we emulate the wait mode via setting the cpu frequency to
+ * the lowest level to put it into the standby mode, which can be waked
+ * up by external interrupts
+ */
+ LOONGSON_SET_CPUFREQ(0);
+
+ /* Resotore it */
+ LOONGSON_CHIPCFG0 = cpufreq;
+
+ /*
+ * report back to the scheduler how long we deep-idled
+ */
+ kt2 = ktime_get_real();
+ idle_time_ns = ktime_to_ns(ktime_sub(kt2, kt1));
+ sched_clock_idle_wakeup_event(idle_time_ns);
+ local_irq_restore(flags);
+}
+
+#endif /* CONFIG_R4K_TIMER_FOR_CPUFREQ */
+
+static inline void register_cpu_wait(void)
+{
+ cpu_wait = loongson2_cpu_wait;
+}
+static inline void unregister_cpu_wait(void)
+{
+ cpu_wait = NULL;
+}
+
+static int l2_cpufreq_target(struct cpufreq_policy *policy, unsigned int
+ target_freq, unsigned int relation)
+{
+ unsigned int newstate;
+ struct cpufreq_freqs freqs;
+
+ if (cpufreq_frequency_table_target(policy, &clockmod_table[0],
+ target_freq, relation, &newstate))
return -EINVAL;
- freq =
- ((cpu_clock_freq / 1000) *
- loongson2_clockmod_table[newstate].index) / 8;
- if (freq < policy->min || freq > policy->max)
- return -EINVAL;
-
- pr_debug("cpufreq: requested frequency %u Hz\n", target_freq * 1000);
-
- freqs.cpu = cpu;
- freqs.old = loongson2_cpufreq_get(cpu);
- freqs.new = freq;
- freqs.flags = 0;
+ freqs.old = l2_cpufreq_get(policy->cpu);
+ freqs.new = idx_to_freq(clockmod_table[newstate].index);
if (freqs.new == freqs.old)
return 0;
/* notifiers */
+ freqs.cpu = policy->cpu;
cpufreq_notify_transition(&freqs, CPUFREQ_PRECHANGE);
- set_cpus_allowed_ptr(current, &cpus_allowed);
-
/* setting the cpu frequency */
- clk_set_rate(cpuclk, freq);
+ l2_cpufreq_set(newstate);
/* notifiers */
cpufreq_notify_transition(&freqs, CPUFREQ_POSTCHANGE);
- pr_debug("cpufreq: set frequency %u kHz\n", freq);
-
return 0;
}
-static int loongson2_cpufreq_cpu_init(struct cpufreq_policy *policy)
+static int l2_cpufreq_cpu_init(struct cpufreq_policy *policy)
{
int i;
- if (!cpu_online(policy->cpu))
- return -ENODEV;
+ /* get max cpu frequency in khz */
+ max_cpufreq_khz = cpu_clock_freq / 1000;
- cpuclk = clk_get(NULL, "cpu_clk");
- if (IS_ERR(cpuclk)) {
- printk(KERN_ERR "cpufreq: couldn't get CPU clk\n");
- return PTR_ERR(cpuclk);
- }
+ /* table init */
+ for (i = 1; clockmod_table[i].index != DC_RESV; i++)
+ clockmod_table[i].frequency = idx_to_freq(clockmod_table[i].index);
- cpuclk->rate = cpu_clock_freq / 1000;
- if (!cpuclk->rate)
- return -EINVAL;
+ cpufreq_frequency_table_get_attr(clockmod_table, policy->cpu);
- /* clock table init */
- for (i = 2;
- (loongson2_clockmod_table[i].frequency != CPUFREQ_TABLE_END);
- i++)
- loongson2_clockmod_table[i].frequency = (cpuclk->rate * i) / 8;
+ /* cpuinfo and default policy values */
- policy->cur = loongson2_cpufreq_get(policy->cpu);
+ policy->cur = max_cpufreq_khz;
- cpufreq_frequency_table_get_attr(&loongson2_clockmod_table[0],
- policy->cpu);
-
- return cpufreq_frequency_table_cpuinfo(policy,
- &loongson2_clockmod_table[0]);
+ return cpufreq_frequency_table_cpuinfo(policy, &clockmod_table[0]);
}
-static int loongson2_cpufreq_verify(struct cpufreq_policy *policy)
+static int l2_cpufreq_verify(struct cpufreq_policy *policy)
{
- return cpufreq_frequency_table_verify(policy,
- &loongson2_clockmod_table[0]);
+ return cpufreq_frequency_table_verify(policy, &clockmod_table[0]);
}
-static int loongson2_cpufreq_exit(struct cpufreq_policy *policy)
+static int l2_cpufreq_cpu_exit(struct cpufreq_policy *policy)
{
- clk_put(cpuclk);
+ cpufreq_frequency_table_put_attr(policy->cpu);
return 0;
}
-static struct freq_attr *loongson2_table_attr[] = {
+static struct freq_attr *clockmod_attr[] = {
&cpufreq_freq_attr_scaling_available_freqs,
NULL,
};
-static struct cpufreq_driver loongson2_cpufreq_driver = {
+static struct cpufreq_driver l2_cpufreq_driver = {
.owner = THIS_MODULE,
- .name = "loongson2",
- .init = loongson2_cpufreq_cpu_init,
- .verify = loongson2_cpufreq_verify,
- .target = loongson2_cpufreq_target,
- .get = loongson2_cpufreq_get,
- .exit = loongson2_cpufreq_exit,
- .attr = loongson2_table_attr,
+ .name = "l2_cpufreq",
+ .init = l2_cpufreq_cpu_init,
+ .exit = l2_cpufreq_cpu_exit,
+ .verify = l2_cpufreq_verify,
+ .target = l2_cpufreq_target,
+ .get = l2_cpufreq_get,
+ .attr = clockmod_attr,
};
static struct platform_device_id platform_device_ids[] = {
{
- .name = "loongson2_cpufreq",
+ .name = "l2_cpufreq",
},
{}
};
-
MODULE_DEVICE_TABLE(platform, platform_device_ids);
static struct platform_driver platform_driver = {
.driver = {
- .name = "loongson2_cpufreq",
+ .name = "l2_cpufreq",
.owner = THIS_MODULE,
},
.id_table = platform_device_ids,
};
-static int __init cpufreq_init(void)
+static int __init l2_cpufreq_init(void)
{
int ret;
@@ -190,38 +308,29 @@
if (ret)
return ret;
- pr_info("cpufreq: Loongson-2F CPU frequency driver.\n");
-
- cpufreq_register_notifier(&loongson2_cpufreq_notifier_block,
- CPUFREQ_TRANSITION_NOTIFIER);
-
- ret = cpufreq_register_driver(&loongson2_cpufreq_driver);
-
- if (!ret && !nowait) {
- saved_cpu_wait = cpu_wait;
- cpu_wait = loongson2_cpu_wait;
+ ret = cpufreq_register_driver(&l2_cpufreq_driver);
+ if (ret) {
+ platform_driver_unregister(&platform_driver);
+ return ret;
}
- return ret;
+ register_cpu_wait();
+
+ return 0;
}
-static void __exit cpufreq_exit(void)
+static void __exit l2_cpufreq_exit(void)
{
- if (!nowait && saved_cpu_wait)
- cpu_wait = saved_cpu_wait;
- cpufreq_unregister_driver(&loongson2_cpufreq_driver);
- cpufreq_unregister_notifier(&loongson2_cpufreq_notifier_block,
- CPUFREQ_TRANSITION_NOTIFIER);
+ unregister_cpu_wait();
+
+ cpufreq_unregister_driver(&l2_cpufreq_driver);
platform_driver_unregister(&platform_driver);
}
-module_init(cpufreq_init);
-module_exit(cpufreq_exit);
+module_init(l2_cpufreq_init);
+module_exit(l2_cpufreq_exit);
-module_param(nowait, uint, 0644);
-MODULE_PARM_DESC(nowait, "Disable Loongson-2F specific wait");
-
-MODULE_AUTHOR("Yanhua <yanh@lemote.com>");
-MODULE_DESCRIPTION("cpufreq driver for Loongson2F");
+MODULE_AUTHOR("Wu Zhangjin <wuzhangjin@gmail.com>");
+MODULE_DESCRIPTION("cpufreq driver for Loongson-2");
MODULE_LICENSE("GPL");
diff --git a/arch/mips/kernel/csrc-r4k.c b/arch/mips/kernel/csrc-r4k.c
index decd1fa..b45a139 100644
--- a/arch/mips/kernel/csrc-r4k.c
+++ b/arch/mips/kernel/csrc-r4k.c
@@ -6,27 +6,236 @@
* 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 <linux/delay.h>
+#include <linux/module.h>
+#include <asm/cpu-features.h>
#include <asm/time.h>
-static cycle_t c0_hpt_read(struct clocksource *cs)
+#include <loongson.h>
+
+/*
+ * Some MIPS cpu can change their frequency, meaning that read_c0_count doesn't
+ * run at the same speed :(
+ * Have to handle this case.
+ */
+#ifdef CONFIG_R4K_TIMER_FOR_CPUFREQ
+
+unsigned int scale_shift;
+EXPORT_SYMBOL(scale_shift);
+#define hpt_scale_up(cycle) ((cycle) << scale_shift)
+
+/*
+ * read_virtual_count -- read the virtual 64bit count
+ *
+ * This should be called with irq disabled and spin lock
+ *
+ * @now: This should be read from the real count register
+ * Return the virtual but precise 64bit count
+ */
+
+static u32 hpt_last_read;
+
+cycle_t notrace read_virtual_count(void)
{
- return read_c0_count();
+ static u64 hpt_last_cnt;
+ u64 diff;
+ unsigned int now;
+ unsigned long flags;
+
+ local_irq_save(flags);
+
+ now = read_c0_count();
+
+ if (unlikely(!hpt_last_read)) {
+ /*
+ * The '1st' time c0_hpt_read() is called so, the cycle read
+ * from the counter is the real one
+ *
+ * When resuming from PM, we also reset it.
+ */
+ hpt_last_cnt = hpt_last_read = now;
+ } else {
+ /* Get diff and Check for counter overflow */
+ diff = (now - hpt_last_read) & CLOCKSOURCE_MASK(32);
+ /* Calculate the real cycles */
+ hpt_last_cnt += hpt_scale_up(diff);
+ /* Save for the next access */
+ hpt_last_read = now;
+ }
+
+ local_irq_restore(flags);
+
+ return hpt_last_cnt;
+}
+
+static inline void reset_virtual_count(void)
+{
+ hpt_last_read = 0;
+}
+
+static void r4k_suspend(struct clocksource *cs)
+{
+}
+
+static void r4k_resume(struct clocksource *cs)
+{
+ reset_virtual_count();
+}
+
+#define hpt_read() read_virtual_count()
+#else
+#define setup_r4k_for_cpufreq(clock)
+#define hpt_read() read_c0_count()
+#define r4k_suspend NULL
+#define r4k_resume NULL
+#endif /* CONFIG_R4K_TIMER_FOR_CPUFREQ */
+
+cycle_t notrace c0_hpt_read(struct clocksource *cs)
+{
+ return hpt_read();
+}
+
+/*
+ * 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;
+
+#ifdef CONFIG_R4K_TIMER_FOR_CPUFREQ
+#define hpt_read64() read_virtual_count()
+#else
+#define hpt_read64() cnt32_to_63(read_c0_count())
+#endif
+unsigned long long notrace sched_clock(void)
+{
+ return (hpt_read64() * clock2ns_scale) >> CLOCK2NS_SCALE_FACTOR;
+}
+
+#ifndef CONFIG_R4K_TIMER_FOR_CPUFREQ
+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)
+{
+ unsigned long long v;
+#ifndef CONFIG_R4K_TIMER_FOR_CPUFREQ
+ unsigned long data;
+#endif
+
+ 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;
+#ifndef CONFIG_R4K_TIMER_FOR_CPUFREQ
+ 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 struct clocksource clocksource_mips = {
.name = "MIPS",
.read = c0_hpt_read,
+#ifdef CONFIG_R4K_TIMER_FOR_CPUFREQ
+ .mask = CLOCKSOURCE_MASK(64),
+ .flags = CLOCK_SOURCE_IS_CONTINUOUS | CLOCK_SOURCE_MUST_VERIFY,
+#else
.mask = CLOCKSOURCE_MASK(32),
.flags = CLOCK_SOURCE_IS_CONTINUOUS,
+#endif
+#ifdef CONFIG_PM
+ .suspend = r4k_suspend,
+ .resume = r4k_resume,
+#endif
};
+static u64 r4k_udelay_factor __read_mostly;
+static u64 r4k_ndelay_factor __read_mostly;
+
+static inline void r4k_setup_delays(void)
+{
+ r4k_udelay_factor = mips_hpt_frequency;
+ do_div(r4k_udelay_factor, 1000000);
+ /*
+ * For __ndelay we divide by 2^16, so the factor is multiplied
+ * by the same amount.
+ */
+ r4k_ndelay_factor = (r4k_udelay_factor * 0x10000ull);
+ do_div(r4k_ndelay_factor, 1000ull);
+
+ lpj_fine = mips_hpt_frequency / HZ;
+}
+
+static inline void rep_nop(void)
+{
+ __asm__ __volatile__("nop;" : : : "memory");
+}
+
+void __delay(unsigned int loops)
+{
+ cycle_t now, bclock;
+
+ preempt_disable();
+ bclock = hpt_read64();
+ for (;;) {
+ now = hpt_read64();
+ if ((now - bclock) >= loops)
+ break;
+ /* Allow RT tasks to run */
+ preempt_enable();
+ rep_nop();
+ preempt_disable();
+ }
+ preempt_enable();
+}
+EXPORT_SYMBOL(__delay);
+
+void __udelay(unsigned int us)
+{
+ __delay(us * r4k_udelay_factor);
+}
+EXPORT_SYMBOL(__udelay);
+
+void __ndelay(unsigned int ns)
+{
+ __delay((ns * r4k_ndelay_factor) >> 16);
+}
+EXPORT_SYMBOL(__ndelay);
+
int __init init_r4k_clocksource(void)
{
if (!cpu_has_counter || !mips_hpt_frequency)
return -ENXIO;
+ r4k_setup_delays();
+
+ setup_hres_sched_clock(mips_hpt_frequency);
+
/* Calculate a somewhat reasonable rating value */
clocksource_mips.rating = 200 + mips_hpt_frequency / 10000000;
diff --git a/arch/mips/kernel/process.c b/arch/mips/kernel/process.c
index b30cb25..ce40b54 100644
--- a/arch/mips/kernel/process.c
+++ b/arch/mips/kernel/process.c
@@ -64,12 +64,12 @@
smtc_idle_loop_hook();
#endif
+ /* Don't trace irqs off for idle */
+ stop_critical_timings();
if (cpu_wait) {
- /* Don't trace irqs off for idle */
- stop_critical_timings();
(*cpu_wait)();
- start_critical_timings();
}
+ start_critical_timings();
}
#ifdef CONFIG_HOTPLUG_CPU
if (!cpu_online(cpu) && !cpu_isset(cpu, cpu_callin_map) &&
diff --git a/arch/mips/kernel/scall64-o32.S b/arch/mips/kernel/scall64-o32.S
index 1d81316..293f1ff 100644
--- a/arch/mips/kernel/scall64-o32.S
+++ b/arch/mips/kernel/scall64-o32.S
@@ -26,6 +26,18 @@
.align 5
NESTED(handle_sys, PT_SIZE, sp)
+#ifdef CONFIG_MIPS_USER_RDTSC
+ MFC0 k0, CP0_EPC
+ lw k1, 0(k0)
+ sltiu k1, k1, 0x1c
+ bne k1, zero, 1f # Normal syscall code: 0x0c < 0x1c
+ nop
+ mfc0 v0, CP0_COUNT # Get TSC
+ PTR_ADDIU k0, 4 # ret from syscall
+ MTC0 k0, CP0_EPC
+ eret
+1:
+#endif /* CONFIG_MIPS_USER_RDTSC */
.set noat
SAVE_SOME
TRACE_IRQS_ON_RELOAD
diff --git a/arch/mips/kernel/spram.c b/arch/mips/kernel/spram.c
index 1821d12..76649b5 100644
--- a/arch/mips/kernel/spram.c
+++ b/arch/mips/kernel/spram.c
@@ -202,7 +202,7 @@
struct cpuinfo_mips *c = ¤t_cpu_data;
unsigned int config0;
- switch (c->cputype) {
+ switch (current_cpu_type()) {
case CPU_24K:
case CPU_34K:
case CPU_74K:
diff --git a/arch/mips/kernel/time.c b/arch/mips/kernel/time.c
index 1083ad4..16a6daa 100644
--- a/arch/mips/kernel/time.c
+++ b/arch/mips/kernel/time.c
@@ -105,7 +105,7 @@
* The published errata for the R4400 up to 3.0 say the CPU
* has the mfc0 from count bug.
*/
- if ((current_cpu_data.processor_id & 0xff) <= 0x30)
+ if (cpu_prid_rev() <= 0x30)
return 1;
/*
@@ -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 --git a/arch/mips/kernel/traps.c b/arch/mips/kernel/traps.c
index cbea618..a8dd1b1 100644
--- a/arch/mips/kernel/traps.c
+++ b/arch/mips/kernel/traps.c
@@ -616,14 +616,14 @@
regs->regs[rt] = smp_processor_id();
return 0;
case 1: /* SYNCI length */
- regs->regs[rt] = min(current_cpu_data.dcache.linesz,
- current_cpu_data.icache.linesz);
+ regs->regs[rt] = min(cpu_dcache_line_size(),
+ cpu_icache_line_size());
return 0;
case 2: /* Read count register */
regs->regs[rt] = read_c0_count();
return 0;
case 3: /* Count register resolution */
- switch (current_cpu_data.cputype) {
+ switch (current_cpu_type()) {
case CPU_20KC:
case CPU_25KF:
regs->regs[rt] = 1;
diff --git a/arch/mips/lib/Makefile b/arch/mips/lib/Makefile
index b2cad4f..e6ebe8b 100644
--- a/arch/mips/lib/Makefile
+++ b/arch/mips/lib/Makefile
@@ -2,9 +2,13 @@
# Makefile for MIPS-specific library files..
#
-lib-y += csum_partial.o delay.o memcpy.o memcpy-inatomic.o memset.o \
+lib-y += csum_partial.o memcpy.o memcpy-inatomic.o memset.o \
strlen_user.o strncpy_user.o strnlen_user.o uncached.o
+ifndef CONFIG_CSRC_R4K
+lib-y += delay.o
+endif
+
obj-y += iomap.o
obj-$(CONFIG_PCI) += iomap-pci.o
diff --git a/arch/mips/loongson/Kconfig b/arch/mips/loongson/Kconfig
index aca93ee..421ae85 100644
--- a/arch/mips/loongson/Kconfig
+++ b/arch/mips/loongson/Kconfig
@@ -32,12 +32,39 @@
config LEMOTE_MACH2F
bool "Lemote Loongson 2F family machines"
+ select ARCH_SPARSEMEM_ENABLE if HIBERNATION
+ select BOARD_SCACHE
+ select BOOT_ELF32
+ select CEVT_R4K if ! MIPS_EXTERNAL_TIMER
+ select CPU_HAS_WB
+ select CS5536 if PCI
+ select CSRC_R4K if ! MIPS_EXTERNAL_TIMER
+ select DMA_NONCOHERENT
+ select GENERIC_ISA_DMA_SUPPORT_BROKEN
+ select HW_HAS_PCI
+ select I8259
+ select IRQ_CPU
+ select SYS_HAS_CPU_LOONGSON2F
+ select SYS_HAS_EARLY_PRINTK
+ select SYS_SUPPORTS_32BIT_KERNEL
+ select SYS_SUPPORTS_64BIT_KERNEL
+ select SYS_SUPPORTS_HIGHMEM if ! EMBEDDED
+ select SYS_SUPPORTS_LITTLE_ENDIAN
+ select LOONGSON_MC146818 if RTC_DRV_CMOS
+ help
+ Lemote Loongson 2F family machines utilize the 2F revision of
+ Loongson processor and the AMD CS5536 south bridge.
+
+ These family machines include fuloong2f mini PC, yeeloong2f notebook,
+ LingLoong allinone PC and so forth.
+
+config DEXXON_GDIUM
+ bool "Dexxon Gdium Netbook"
select ARCH_SPARSEMEM_ENABLE
select BOARD_SCACHE
select BOOT_ELF32
select CEVT_R4K if ! MIPS_EXTERNAL_TIMER
select CPU_HAS_WB
- select CS5536
select CSRC_R4K if ! MIPS_EXTERNAL_TIMER
select DMA_NONCOHERENT
select GENERIC_ISA_DMA_SUPPORT_BROKEN
@@ -51,42 +78,75 @@
select SYS_SUPPORTS_64BIT_KERNEL
select SYS_SUPPORTS_HIGHMEM
select SYS_SUPPORTS_LITTLE_ENDIAN
- select LOONGSON_MC146818
+ select ARCH_REQUIRE_GPIOLIB
+ select HAVE_PWM if MFD_SM501
help
- Lemote Loongson 2F family machines utilize the 2F revision of
- Loongson processor and the AMD CS5536 south bridge.
-
- These family machines include fuloong2f mini PC, yeeloong2f notebook,
- LingLoong allinone PC and so forth.
+ Dexxon gdium netbook based on Loongson 2F and SM502.
endchoice
config CS5536
+ select CS5536_IDE if (PATA_AMD || BLK_DEV_AMD74XX || PATA_CS5536)
+ select CS5536_OHCI if USB_OHCI_HCD
+ select CS5536_EHCI if USB_EHCI_HCD
+ select CS5536_AUDIO if SND_CS5535AUDIO
+ select CS5536_ISA
+ bool
+
+config CS5536_ISA
+ select ISA
+ bool
+
+config CS5536_IDE
+ bool
+
+config CS5536_OHCI
+ bool
+
+config CS5536_EHCI
+ bool
+
+config CS5536_AUDIO
bool
config CS5536_MFGPT
bool "CS5536 MFGPT Timer"
+ depends on BROKEN
depends on CS5536
select MIPS_EXTERNAL_TIMER
help
This option enables the mfgpt0 timer of AMD CS5536.
- If you want to enable the Loongson2 CPUFreq Driver, Please enable
- this option at first, otherwise, You will get wrong system time.
+ To enable the Loongson2 CPUFreq Driver, this option is a
+ precondition, but from 2.6.37, we have a better choice, that is
+ CONFIG_R4K_TIMER_FOR_CPUFREQ=y. To get a good CPUFreq driver, that
+ option should be enabled with the ondemand governor.
- If unsure, say Yes.
+ If unsure, say NO.
config LOONGSON_SUSPEND
bool
default y
depends on CPU_SUPPORTS_CPUFREQ && SUSPEND
-config LOONGSON_UART_BASE
- bool
- default y
- depends on EARLY_PRINTK || SERIAL_8250
-
config LOONGSON_MC146818
bool
default n
+config GDIUM_PWM_CLOCK
+ tristate "Gdium PWM Timer"
+ default n
+ depends on HAVE_PWM && EXPERIMENTAL && BROKEN
+ select MIPS_EXTERNAL_TIMER
+ help
+ This options enables the experimental sm501-pwm based clock. With it,
+ you may be possible to use the loongson2f cpufreq driver.
+
+config GDIUM_VERSION
+ int "Configure Gdium Version"
+ depends on DEXXON_GDIUM
+ default "3"
+ help
+ I have no information about how to determine which version your board
+ is, If the default config doesn't work for it, please change it to
+ smaller ones.
endif # MACH_LOONGSON
diff --git a/arch/mips/loongson/Makefile b/arch/mips/loongson/Makefile
index 2b76cb0..1c3ae7c 100644
--- a/arch/mips/loongson/Makefile
+++ b/arch/mips/loongson/Makefile
@@ -15,3 +15,9 @@
#
obj-$(CONFIG_LEMOTE_MACH2F) += lemote-2f/
+
+#
+# Dexxon gdium netbook, based on loongson 2F and SM502
+#
+
+obj-$(CONFIG_DEXXON_GDIUM) += gdium/
diff --git a/arch/mips/loongson/Platform b/arch/mips/loongson/Platform
index 29692e5..6be5dff 100644
--- a/arch/mips/loongson/Platform
+++ b/arch/mips/loongson/Platform
@@ -30,3 +30,4 @@
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_DEXXON_GDIUM) += 0xffffffff80200000
diff --git a/arch/mips/loongson/common/Makefile b/arch/mips/loongson/common/Makefile
index e526488..ed90596 100644
--- a/arch/mips/loongson/common/Makefile
+++ b/arch/mips/loongson/common/Makefile
@@ -3,7 +3,10 @@
#
obj-y += setup.o init.o cmdline.o env.o time.o reset.o irq.o \
- pci.o bonito-irq.o mem.o machtype.o platform.o
+ bonito-irq.o mem.o machtype.o platform.o
+
+obj-$(CONFIG_PCI) += pci.o
+
obj-$(CONFIG_GENERIC_GPIO) += gpio.o
#
@@ -11,7 +14,6 @@
#
obj-$(CONFIG_EARLY_PRINTK) += early_printk.o
obj-$(CONFIG_SERIAL_8250) += serial.o
-obj-$(CONFIG_LOONGSON_UART_BASE) += uart_base.o
obj-$(CONFIG_LOONGSON_MC146818) += rtc.o
#
diff --git a/arch/mips/loongson/common/cmdline.c b/arch/mips/loongson/common/cmdline.c
index 353e1d2..8bce6a8 100644
--- a/arch/mips/loongson/common/cmdline.c
+++ b/arch/mips/loongson/common/cmdline.c
@@ -17,10 +17,15 @@
* 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>
+/* 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;
@@ -45,4 +50,31 @@
}
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;
+ case MACH_DEXXON_GDIUM2F10:
+ /* gdium has a 1024x600 screen */
+ if ((strstr(arcs_cmdline, "video=")) == NULL)
+ strcat(arcs_cmdline, " video=sm501fb:1024x600@60");
+ break;
+ default:
+ break;
+ }
+
+ /* copy arcs_cmdline into loongson_cmdline */
+ strncpy(loongson_cmdline, arcs_cmdline, COMMAND_LINE_SIZE);
}
diff --git a/arch/mips/loongson/common/cs5536/Makefile b/arch/mips/loongson/common/cs5536/Makefile
index f12e640..70f6057 100644
--- a/arch/mips/loongson/common/cs5536/Makefile
+++ b/arch/mips/loongson/common/cs5536/Makefile
@@ -2,8 +2,13 @@
# Makefile for CS5536 support.
#
-obj-$(CONFIG_CS5536) += cs5536_pci.o cs5536_ide.o cs5536_acc.o cs5536_ohci.o \
- cs5536_isa.o cs5536_ehci.o
+obj-$(CONFIG_CS5536) += cs5536_pci.o
+
+obj-$(CONFIG_ISA) += cs5536_isa.o
+obj-$(CONFIG_CS5536_IDE) += cs5536_ide.o
+obj-$(CONFIG_CS5536_AUDIO) += cs5536_acc.o
+obj-$(CONFIG_CS5536_OHCI) += cs5536_ohci.o
+obj-$(CONFIG_CS5536_EHCI) += cs5536_ehci.o
#
# Enable cs5536 mfgpt Timer
diff --git a/arch/mips/loongson/common/cs5536/cs5536_acc.c b/arch/mips/loongson/common/cs5536/cs5536_acc.c
index b3fd5ea..602b539 100644
--- a/arch/mips/loongson/common/cs5536/cs5536_acc.c
+++ b/arch/mips/loongson/common/cs5536/cs5536_acc.c
@@ -18,7 +18,7 @@
void pci_acc_write_reg(int reg, u32 value)
{
- u32 hi = 0, lo = value;
+ u32 hi, lo;
switch (reg) {
case PCI_COMMAND:
@@ -66,75 +66,73 @@
u32 pci_acc_read_reg(int reg)
{
u32 hi, lo;
- u32 conf_data = 0;
+ u32 cfg = 0;
switch (reg) {
case PCI_VENDOR_ID:
- conf_data =
- CFG_PCI_VENDOR_ID(CS5536_ACC_DEVICE_ID, CS5536_VENDOR_ID);
+ cfg = CFG_PCI_VENDOR_ID(PCI_DEVICE_ID_AMD_CS5536_AUDIO,
+ PCI_VENDOR_ID_AMD);
break;
case PCI_COMMAND:
_rdmsr(GLIU_MSR_REG(GLIU_IOD_BM1), &hi, &lo);
if (((lo & 0xfff00000) || (hi & 0x000000ff))
&& ((hi & 0xf0000000) == 0xa0000000))
- conf_data |= PCI_COMMAND_IO;
+ cfg |= PCI_COMMAND_IO;
_rdmsr(GLIU_MSR_REG(GLIU_PAE), &hi, &lo);
if ((lo & 0x300) == 0x300)
- conf_data |= PCI_COMMAND_MASTER;
+ cfg |= PCI_COMMAND_MASTER;
break;
case PCI_STATUS:
- conf_data |= PCI_STATUS_66MHZ;
- conf_data |= PCI_STATUS_FAST_BACK;
+ cfg |= PCI_STATUS_66MHZ;
+ cfg |= PCI_STATUS_FAST_BACK;
_rdmsr(SB_MSR_REG(SB_ERROR), &hi, &lo);
if (lo & SB_PARE_ERR_FLAG)
- conf_data |= PCI_STATUS_PARITY;
- conf_data |= PCI_STATUS_DEVSEL_MEDIUM;
+ cfg |= PCI_STATUS_PARITY;
+ cfg |= PCI_STATUS_DEVSEL_MEDIUM;
break;
case PCI_CLASS_REVISION:
_rdmsr(ACC_MSR_REG(ACC_CAP), &hi, &lo);
- conf_data = lo & 0x000000ff;
- conf_data |= (CS5536_ACC_CLASS_CODE << 8);
+ cfg = lo & 0x000000ff;
+ cfg |= (CS5536_ACC_CLASS_CODE << 8);
break;
case PCI_CACHE_LINE_SIZE:
- conf_data =
- CFG_PCI_CACHE_LINE_SIZE(PCI_NORMAL_HEADER_TYPE,
- PCI_NORMAL_LATENCY_TIMER);
+ cfg = CFG_PCI_CACHE_LINE_SIZE(PCI_NORMAL_HEADER_TYPE,
+ PCI_NORMAL_LATENCY_TIMER);
break;
case PCI_BAR0_REG:
_rdmsr(GLCP_MSR_REG(GLCP_SOFT_COM), &hi, &lo);
if (lo & SOFT_BAR_ACC_FLAG) {
- conf_data = CS5536_ACC_RANGE |
+ cfg = CS5536_ACC_RANGE |
PCI_BASE_ADDRESS_SPACE_IO;
lo &= ~SOFT_BAR_ACC_FLAG;
_wrmsr(GLCP_MSR_REG(GLCP_SOFT_COM), hi, lo);
} else {
_rdmsr(GLIU_MSR_REG(GLIU_IOD_BM1), &hi, &lo);
- conf_data = (hi & 0x000000ff) << 12;
- conf_data |= (lo & 0xfff00000) >> 20;
- conf_data |= 0x01;
- conf_data &= ~0x02;
+ cfg = (hi & 0x000000ff) << 12;
+ cfg |= (lo & 0xfff00000) >> 20;
+ cfg |= 0x01;
+ cfg &= ~0x02;
}
break;
case PCI_CARDBUS_CIS:
- conf_data = PCI_CARDBUS_CIS_POINTER;
+ cfg = PCI_CARDBUS_CIS_POINTER;
break;
case PCI_SUBSYSTEM_VENDOR_ID:
- conf_data =
- CFG_PCI_VENDOR_ID(CS5536_ACC_SUB_ID, CS5536_SUB_VENDOR_ID);
+ cfg = CFG_PCI_VENDOR_ID(PCI_DEVICE_ID_AMD_CS5536_AUDIO,
+ PCI_VENDOR_ID_AMD);
break;
case PCI_ROM_ADDRESS:
- conf_data = PCI_EXPANSION_ROM_BAR;
+ cfg = PCI_EXPANSION_ROM_BAR;
break;
case PCI_CAPABILITY_LIST:
- conf_data = PCI_CAPLIST_USB_POINTER;
+ cfg = PCI_CAPLIST_USB_POINTER;
break;
case PCI_INTERRUPT_LINE:
- conf_data =
- CFG_PCI_INTERRUPT_LINE(PCI_DEFAULT_PIN, CS5536_ACC_INTR);
+ cfg = CFG_PCI_INTERRUPT_LINE(PCI_DEFAULT_PIN, CS5536_ACC_INTR);
break;
default:
break;
}
- return conf_data;
+ return cfg;
}
diff --git a/arch/mips/loongson/common/cs5536/cs5536_ehci.c b/arch/mips/loongson/common/cs5536/cs5536_ehci.c
index 5b5cbba..0fd49b8 100644
--- a/arch/mips/loongson/common/cs5536/cs5536_ehci.c
+++ b/arch/mips/loongson/common/cs5536/cs5536_ehci.c
@@ -18,7 +18,7 @@
void pci_ehci_write_reg(int reg, u32 value)
{
- u32 hi = 0, lo = value;
+ u32 hi, lo;
switch (reg) {
case PCI_COMMAND:
@@ -78,83 +78,78 @@
u32 pci_ehci_read_reg(int reg)
{
- u32 conf_data = 0;
+ u32 cfg = 0;
u32 hi, lo;
switch (reg) {
case PCI_VENDOR_ID:
- conf_data =
- CFG_PCI_VENDOR_ID(CS5536_EHCI_DEVICE_ID, CS5536_VENDOR_ID);
+ case PCI_SUBSYSTEM_VENDOR_ID:
+ cfg = CFG_PCI_VENDOR_ID(PCI_DEVICE_ID_AMD_CS5536_EHC,
+ PCI_VENDOR_ID_AMD);
break;
case PCI_COMMAND:
_rdmsr(USB_MSR_REG(USB_EHCI), &hi, &lo);
if (hi & PCI_COMMAND_MASTER)
- conf_data |= PCI_COMMAND_MASTER;
+ cfg |= PCI_COMMAND_MASTER;
if (hi & PCI_COMMAND_MEMORY)
- conf_data |= PCI_COMMAND_MEMORY;
+ cfg |= PCI_COMMAND_MEMORY;
break;
case PCI_STATUS:
- conf_data |= PCI_STATUS_66MHZ;
- conf_data |= PCI_STATUS_FAST_BACK;
+ cfg |= PCI_STATUS_66MHZ;
+ cfg |= PCI_STATUS_FAST_BACK;
_rdmsr(SB_MSR_REG(SB_ERROR), &hi, &lo);
if (lo & SB_PARE_ERR_FLAG)
- conf_data |= PCI_STATUS_PARITY;
- conf_data |= PCI_STATUS_DEVSEL_MEDIUM;
+ cfg |= PCI_STATUS_PARITY;
+ cfg |= PCI_STATUS_DEVSEL_MEDIUM;
break;
case PCI_CLASS_REVISION:
_rdmsr(USB_MSR_REG(USB_CAP), &hi, &lo);
- conf_data = lo & 0x000000ff;
- conf_data |= (CS5536_EHCI_CLASS_CODE << 8);
+ cfg = lo & 0x000000ff;
+ cfg |= (CS5536_EHCI_CLASS_CODE << 8);
break;
case PCI_CACHE_LINE_SIZE:
- conf_data =
- CFG_PCI_CACHE_LINE_SIZE(PCI_NORMAL_HEADER_TYPE,
- PCI_NORMAL_LATENCY_TIMER);
+ cfg = CFG_PCI_CACHE_LINE_SIZE(PCI_NORMAL_HEADER_TYPE,
+ PCI_NORMAL_LATENCY_TIMER);
break;
case PCI_BAR0_REG:
_rdmsr(GLCP_MSR_REG(GLCP_SOFT_COM), &hi, &lo);
if (lo & SOFT_BAR_EHCI_FLAG) {
- conf_data = CS5536_EHCI_RANGE |
+ cfg = CS5536_EHCI_RANGE |
PCI_BASE_ADDRESS_SPACE_MEMORY;
lo &= ~SOFT_BAR_EHCI_FLAG;
_wrmsr(GLCP_MSR_REG(GLCP_SOFT_COM), hi, lo);
} else {
_rdmsr(USB_MSR_REG(USB_EHCI), &hi, &lo);
- conf_data = lo & 0xfffff000;
+ cfg = lo & 0xfffff000;
}
break;
case PCI_CARDBUS_CIS:
- conf_data = PCI_CARDBUS_CIS_POINTER;
- break;
- case PCI_SUBSYSTEM_VENDOR_ID:
- conf_data =
- CFG_PCI_VENDOR_ID(CS5536_EHCI_SUB_ID, CS5536_SUB_VENDOR_ID);
+ cfg = PCI_CARDBUS_CIS_POINTER;
break;
case PCI_ROM_ADDRESS:
- conf_data = PCI_EXPANSION_ROM_BAR;
+ cfg = PCI_EXPANSION_ROM_BAR;
break;
case PCI_CAPABILITY_LIST:
- conf_data = PCI_CAPLIST_USB_POINTER;
+ cfg = PCI_CAPLIST_USB_POINTER;
break;
case PCI_INTERRUPT_LINE:
- conf_data =
- CFG_PCI_INTERRUPT_LINE(PCI_DEFAULT_PIN, CS5536_USB_INTR);
+ cfg = CFG_PCI_INTERRUPT_LINE(PCI_DEFAULT_PIN, CS5536_USB_INTR);
break;
case PCI_EHCI_LEGSMIEN_REG:
_rdmsr(USB_MSR_REG(USB_EHCI), &hi, &lo);
- conf_data = (hi & 0x003f0000) >> 16;
+ cfg = (hi & 0x003f0000) >> 16;
break;
case PCI_EHCI_LEGSMISTS_REG:
_rdmsr(USB_MSR_REG(USB_EHCI), &hi, &lo);
- conf_data = (hi & 0x3f000000) >> 24;
+ cfg = (hi & 0x3f000000) >> 24;
break;
case PCI_EHCI_FLADJ_REG:
_rdmsr(USB_MSR_REG(USB_EHCI), &hi, &lo);
- conf_data = hi & 0x00003f00;
+ cfg = hi & 0x00003f00;
break;
default:
break;
}
- return conf_data;
+ return cfg;
}
diff --git a/arch/mips/loongson/common/cs5536/cs5536_ide.c b/arch/mips/loongson/common/cs5536/cs5536_ide.c
index 681d129..32ad4ee 100644
--- a/arch/mips/loongson/common/cs5536/cs5536_ide.c
+++ b/arch/mips/loongson/common/cs5536/cs5536_ide.c
@@ -18,7 +18,7 @@
void pci_ide_write_reg(int reg, u32 value)
{
- u32 hi = 0, lo = value;
+ u32 hi, lo;
switch (reg) {
case PCI_COMMAND:
@@ -72,26 +72,16 @@
_wrmsr(IDE_MSR_REG(IDE_CFG), hi, lo);
}
break;
- case PCI_IDE_DTC_REG:
- _rdmsr(IDE_MSR_REG(IDE_DTC), &hi, &lo);
- lo = value;
- _wrmsr(IDE_MSR_REG(IDE_DTC), hi, lo);
+#define SET_PCI_IDE_REG(r) \
+ case PCI_IDE_##r##_REG: \
+ _rdmsr(IDE_MSR_REG(IDE_##r), &hi, &lo); \
+ lo = value; \
+ _wrmsr(IDE_MSR_REG(IDE_##r), hi, lo); \
break;
- case PCI_IDE_CAST_REG:
- _rdmsr(IDE_MSR_REG(IDE_CAST), &hi, &lo);
- lo = value;
- _wrmsr(IDE_MSR_REG(IDE_CAST), hi, lo);
- break;
- case PCI_IDE_ETC_REG:
- _rdmsr(IDE_MSR_REG(IDE_ETC), &hi, &lo);
- lo = value;
- _wrmsr(IDE_MSR_REG(IDE_ETC), hi, lo);
- break;
- case PCI_IDE_PM_REG:
- _rdmsr(IDE_MSR_REG(IDE_INTERNAL_PM), &hi, &lo);
- lo = value;
- _wrmsr(IDE_MSR_REG(IDE_INTERNAL_PM), hi, lo);
- break;
+ SET_PCI_IDE_REG(DTC)
+ SET_PCI_IDE_REG(CAST)
+ SET_PCI_IDE_REG(ETC)
+ SET_PCI_IDE_REG(PM)
default:
break;
}
@@ -99,94 +89,79 @@
u32 pci_ide_read_reg(int reg)
{
- u32 conf_data = 0;
+ u32 cfg = 0;
u32 hi, lo;
switch (reg) {
case PCI_VENDOR_ID:
- conf_data =
- CFG_PCI_VENDOR_ID(CS5536_IDE_DEVICE_ID, CS5536_VENDOR_ID);
+ case PCI_SUBSYSTEM_VENDOR_ID:
+ cfg = CFG_PCI_VENDOR_ID(PCI_DEVICE_ID_AMD_CS5536_IDE,
+ PCI_VENDOR_ID_AMD);
break;
case PCI_COMMAND:
_rdmsr(IDE_MSR_REG(IDE_IO_BAR), &hi, &lo);
if (lo & 0xfffffff0)
- conf_data |= PCI_COMMAND_IO;
+ cfg |= PCI_COMMAND_IO;
_rdmsr(GLIU_MSR_REG(GLIU_PAE), &hi, &lo);
if ((lo & 0x30) == 0x30)
- conf_data |= PCI_COMMAND_MASTER;
+ cfg |= PCI_COMMAND_MASTER;
break;
case PCI_STATUS:
- conf_data |= PCI_STATUS_66MHZ;
- conf_data |= PCI_STATUS_FAST_BACK;
+ cfg |= PCI_STATUS_66MHZ;
+ cfg |= PCI_STATUS_FAST_BACK;
_rdmsr(SB_MSR_REG(SB_ERROR), &hi, &lo);
if (lo & SB_PARE_ERR_FLAG)
- conf_data |= PCI_STATUS_PARITY;
- conf_data |= PCI_STATUS_DEVSEL_MEDIUM;
+ cfg |= PCI_STATUS_PARITY;
+ cfg |= PCI_STATUS_DEVSEL_MEDIUM;
break;
case PCI_CLASS_REVISION:
_rdmsr(IDE_MSR_REG(IDE_CAP), &hi, &lo);
- conf_data = lo & 0x000000ff;
- conf_data |= (CS5536_IDE_CLASS_CODE << 8);
+ cfg = lo & 0x000000ff;
+ cfg |= (CS5536_IDE_CLASS_CODE << 8);
break;
case PCI_CACHE_LINE_SIZE:
_rdmsr(SB_MSR_REG(SB_CTRL), &hi, &lo);
hi &= 0x000000f8;
- conf_data = CFG_PCI_CACHE_LINE_SIZE(PCI_NORMAL_HEADER_TYPE, hi);
+ cfg = CFG_PCI_CACHE_LINE_SIZE(PCI_NORMAL_HEADER_TYPE, hi);
break;
case PCI_BAR4_REG:
_rdmsr(GLCP_MSR_REG(GLCP_SOFT_COM), &hi, &lo);
if (lo & SOFT_BAR_IDE_FLAG) {
- conf_data = CS5536_IDE_RANGE |
+ cfg = CS5536_IDE_RANGE |
PCI_BASE_ADDRESS_SPACE_IO;
lo &= ~SOFT_BAR_IDE_FLAG;
_wrmsr(GLCP_MSR_REG(GLCP_SOFT_COM), hi, lo);
} else {
_rdmsr(IDE_MSR_REG(IDE_IO_BAR), &hi, &lo);
- conf_data = lo & 0xfffffff0;
- conf_data |= 0x01;
- conf_data &= ~0x02;
+ cfg = lo & 0xfffffff0;
+ cfg |= 0x01;
+ cfg &= ~0x02;
}
break;
case PCI_CARDBUS_CIS:
- conf_data = PCI_CARDBUS_CIS_POINTER;
- break;
- case PCI_SUBSYSTEM_VENDOR_ID:
- conf_data =
- CFG_PCI_VENDOR_ID(CS5536_IDE_SUB_ID, CS5536_SUB_VENDOR_ID);
+ cfg = PCI_CARDBUS_CIS_POINTER;
break;
case PCI_ROM_ADDRESS:
- conf_data = PCI_EXPANSION_ROM_BAR;
+ cfg = PCI_EXPANSION_ROM_BAR;
break;
case PCI_CAPABILITY_LIST:
- conf_data = PCI_CAPLIST_POINTER;
+ cfg = PCI_CAPLIST_POINTER;
break;
case PCI_INTERRUPT_LINE:
- conf_data =
- CFG_PCI_INTERRUPT_LINE(PCI_DEFAULT_PIN, CS5536_IDE_INTR);
+ cfg = CFG_PCI_INTERRUPT_LINE(PCI_DEFAULT_PIN, CS5536_IDE_INTR);
break;
- case PCI_IDE_CFG_REG:
- _rdmsr(IDE_MSR_REG(IDE_CFG), &hi, &lo);
- conf_data = lo;
+#define GET_PCI_IDE_REG(r) \
+ case PCI_IDE_##r##_REG: \
+ _rdmsr(IDE_MSR_REG(IDE_##r), &hi, &cfg); \
break;
- case PCI_IDE_DTC_REG:
- _rdmsr(IDE_MSR_REG(IDE_DTC), &hi, &lo);
- conf_data = lo;
- break;
- case PCI_IDE_CAST_REG:
- _rdmsr(IDE_MSR_REG(IDE_CAST), &hi, &lo);
- conf_data = lo;
- break;
- case PCI_IDE_ETC_REG:
- _rdmsr(IDE_MSR_REG(IDE_ETC), &hi, &lo);
- conf_data = lo;
- break;
- case PCI_IDE_PM_REG:
- _rdmsr(IDE_MSR_REG(IDE_INTERNAL_PM), &hi, &lo);
- conf_data = lo;
- break;
+ GET_PCI_IDE_REG(CFG)
+ GET_PCI_IDE_REG(DTC)
+ GET_PCI_IDE_REG(CAST)
+ GET_PCI_IDE_REG(ETC)
+ GET_PCI_IDE_REG(PM)
default:
break;
}
- return conf_data;
+ return cfg;
}
diff --git a/arch/mips/loongson/common/cs5536/cs5536_isa.c b/arch/mips/loongson/common/cs5536/cs5536_isa.c
index 4d9f65a..3469f64 100644
--- a/arch/mips/loongson/common/cs5536/cs5536_isa.c
+++ b/arch/mips/loongson/common/cs5536/cs5536_isa.c
@@ -86,7 +86,7 @@
void pci_isa_write_bar(int n, u32 value)
{
- u32 hi = 0, lo = value;
+ u32 hi, lo;
if (value == PCI_BAR_RANGE_MASK) {
_rdmsr(GLCP_MSR_REG(GLCP_SOFT_COM), &hi, &lo);
@@ -95,7 +95,7 @@
} else if (value & 0x01) {
/* NATIVE reg */
hi = 0x0000f001;
- lo &= bar_space_range[n];
+ lo = value & bar_space_range[n];
_wrmsr(divil_msr_reg[n], hi, lo);
/* RCONFx is 4bytes in units for I/O space */
@@ -112,21 +112,21 @@
u32 pci_isa_read_bar(int n)
{
- u32 conf_data = 0;
+ u32 cfg = 0;
u32 hi, lo;
_rdmsr(GLCP_MSR_REG(GLCP_SOFT_COM), &hi, &lo);
if (lo & soft_bar_flag[n]) {
- conf_data = bar_space_range[n] | PCI_BASE_ADDRESS_SPACE_IO;
+ cfg = bar_space_range[n] | PCI_BASE_ADDRESS_SPACE_IO;
lo &= ~soft_bar_flag[n];
_wrmsr(GLCP_MSR_REG(GLCP_SOFT_COM), hi, lo);
} else {
_rdmsr(divil_msr_reg[n], &hi, &lo);
- conf_data = lo & bar_space_range[n];
- conf_data |= 0x01;
- conf_data &= ~0x02;
+ cfg = lo & bar_space_range[n];
+ cfg |= 0x01;
+ cfg &= ~0x02;
}
- return conf_data;
+ return cfg;
}
/*
@@ -136,7 +136,7 @@
*/
void pci_isa_write_reg(int reg, u32 value)
{
- u32 hi = 0, lo = value;
+ u32 hi, lo;
u32 temp;
switch (reg) {
@@ -230,45 +230,46 @@
*/
u32 pci_isa_read_reg(int reg)
{
- u32 conf_data = 0;
+ u32 cfg = 0;
u32 hi, lo;
switch (reg) {
case PCI_VENDOR_ID:
- conf_data =
- CFG_PCI_VENDOR_ID(CS5536_ISA_DEVICE_ID, CS5536_VENDOR_ID);
+ case PCI_SUBSYSTEM_VENDOR_ID:
+ cfg = CFG_PCI_VENDOR_ID(PCI_DEVICE_ID_AMD_CS5536_ISA,
+ PCI_VENDOR_ID_AMD);
break;
case PCI_COMMAND:
/* we just check the first LBAR for the IO enable bit, */
/* maybe we should changed later. */
_rdmsr(DIVIL_MSR_REG(DIVIL_LBAR_SMB), &hi, &lo);
if (hi & 0x01)
- conf_data |= PCI_COMMAND_IO;
+ cfg |= PCI_COMMAND_IO;
break;
case PCI_STATUS:
- conf_data |= PCI_STATUS_66MHZ;
- conf_data |= PCI_STATUS_DEVSEL_MEDIUM;
- conf_data |= PCI_STATUS_FAST_BACK;
+ cfg |= PCI_STATUS_66MHZ;
+ cfg |= PCI_STATUS_DEVSEL_MEDIUM;
+ cfg |= PCI_STATUS_FAST_BACK;
_rdmsr(SB_MSR_REG(SB_ERROR), &hi, &lo);
if (lo & SB_TAS_ERR_FLAG)
- conf_data |= PCI_STATUS_SIG_TARGET_ABORT;
+ cfg |= PCI_STATUS_SIG_TARGET_ABORT;
if (lo & SB_TAR_ERR_FLAG)
- conf_data |= PCI_STATUS_REC_TARGET_ABORT;
+ cfg |= PCI_STATUS_REC_TARGET_ABORT;
if (lo & SB_MAR_ERR_FLAG)
- conf_data |= PCI_STATUS_REC_MASTER_ABORT;
+ cfg |= PCI_STATUS_REC_MASTER_ABORT;
if (lo & SB_PARE_ERR_FLAG)
- conf_data |= PCI_STATUS_DETECTED_PARITY;
+ cfg |= PCI_STATUS_DETECTED_PARITY;
break;
case PCI_CLASS_REVISION:
_rdmsr(GLCP_MSR_REG(GLCP_CHIP_REV_ID), &hi, &lo);
- conf_data = lo & 0x000000ff;
- conf_data |= (CS5536_ISA_CLASS_CODE << 8);
+ cfg = lo & 0x000000ff;
+ cfg |= (CS5536_ISA_CLASS_CODE << 8);
break;
case PCI_CACHE_LINE_SIZE:
_rdmsr(SB_MSR_REG(SB_CTRL), &hi, &lo);
hi &= 0x000000f8;
- conf_data = CFG_PCI_CACHE_LINE_SIZE(PCI_BRIDGE_HEADER_TYPE, hi);
+ cfg = CFG_PCI_CACHE_LINE_SIZE(PCI_BRIDGE_HEADER_TYPE, hi);
break;
/*
* we only use the LBAR of DIVIL, no RCONF used.
@@ -292,25 +293,21 @@
return pci_isa_read_bar(5);
break;
case PCI_CARDBUS_CIS:
- conf_data = PCI_CARDBUS_CIS_POINTER;
- break;
- case PCI_SUBSYSTEM_VENDOR_ID:
- conf_data =
- CFG_PCI_VENDOR_ID(CS5536_ISA_SUB_ID, CS5536_SUB_VENDOR_ID);
+ cfg = PCI_CARDBUS_CIS_POINTER;
break;
case PCI_ROM_ADDRESS:
- conf_data = PCI_EXPANSION_ROM_BAR;
+ cfg = PCI_EXPANSION_ROM_BAR;
break;
case PCI_CAPABILITY_LIST:
- conf_data = PCI_CAPLIST_POINTER;
+ cfg = PCI_CAPLIST_POINTER;
break;
case PCI_INTERRUPT_LINE:
/* no interrupt used here */
- conf_data = CFG_PCI_INTERRUPT_LINE(0x00, 0x00);
+ cfg = CFG_PCI_INTERRUPT_LINE(0x00, 0x00);
break;
default:
break;
}
- return conf_data;
+ return cfg;
}
diff --git a/arch/mips/loongson/common/cs5536/cs5536_mfgpt.c b/arch/mips/loongson/common/cs5536/cs5536_mfgpt.c
index 0cb1b97..c949dd9 100644
--- a/arch/mips/loongson/common/cs5536/cs5536_mfgpt.c
+++ b/arch/mips/loongson/common/cs5536/cs5536_mfgpt.c
@@ -7,6 +7,9 @@
* Copyright (C) 2009 Lemote Inc.
* Author: Wu zhangjin, wuzhangjin@gmail.com
*
+ * Copyright (C) 2010 Lemote Inc.
+ * Author: Gang Liang, randomizedthinking@gmail.com
+ *
* Reference: AMD Geode(TM) CS5536 Companion Device Data Book
*
* This program is free software; you can redistribute it and/or modify it
@@ -15,11 +18,24 @@
* option) any later version.
*/
+/*
+ * The MFGPT base address is variable, i.e., it could change over time. In
+ * reality, it only changes once when setting up the PCI memory mapping (occurs
+ * about 0.2 second from boot). But because of this, we have to read in the
+ * mfgpt base address repeatly in the beginning of various routines, most
+ * noticeably, mfgpt1_read_cycle (for sched_clock), and mfgpt1_interrupt.
+ *
+ * The source of problem is that PMON and the current cs5536 set up pci
+ * register window differently (to be further confirmed). Can we set
+ * them the same so as to save the trouble here?
+ *
+ * Now an ugly hack is used to save a few CPU cycles... likely an
+ * over-optimization. Feel free to remove it.
+ */
+
#include <linux/io.h>
#include <linux/init.h>
#include <linux/module.h>
-#include <linux/jiffies.h>
-#include <linux/spinlock.h>
#include <linux/interrupt.h>
#include <linux/clockchips.h>
@@ -27,93 +43,127 @@
#include <cs5536/cs5536_mfgpt.h>
-DEFINE_SPINLOCK(mfgpt_lock);
-EXPORT_SYMBOL(mfgpt_lock);
+static void mfgpt0_set_mode(enum clock_event_mode, struct clock_event_device*);
+static int mfgpt0_next_event(unsigned long, struct clock_event_device*);
+static irqreturn_t mfgpt0_interrupt(int irq, void *dev_id);
+static void mfgpt0_start_timer(u16 delta);
+static cycle_t mfgpt1_read_cycle(struct clocksource *cs);
+
+static enum clock_event_mode mfgpt0_mode = CLOCK_EVT_MODE_SHUTDOWN;
static u32 mfgpt_base;
-/*
- * Initialize the MFGPT timer.
- *
- * This is also called after resume to bring the MFGPT into operation again.
- */
-
-/* disable counter */
-void disable_mfgpt0_counter(void)
-{
- outw(inw(MFGPT0_SETUP) & 0x7fff, MFGPT0_SETUP);
-}
-EXPORT_SYMBOL(disable_mfgpt0_counter);
-
-/* enable counter, comparator2 to event mode, 14.318MHz clock */
-void enable_mfgpt0_counter(void)
-{
- outw(0xe310, MFGPT0_SETUP);
-}
-EXPORT_SYMBOL(enable_mfgpt0_counter);
-
-static void init_mfgpt_timer(enum clock_event_mode mode,
- struct clock_event_device *evt)
-{
- spin_lock(&mfgpt_lock);
-
- switch (mode) {
- case CLOCK_EVT_MODE_PERIODIC:
- outw(COMPARE, MFGPT0_CMP2); /* set comparator2 */
- outw(0, MFGPT0_CNT); /* set counter to 0 */
- enable_mfgpt0_counter();
- break;
-
- case CLOCK_EVT_MODE_SHUTDOWN:
- case CLOCK_EVT_MODE_UNUSED:
- if (evt->mode == CLOCK_EVT_MODE_PERIODIC ||
- evt->mode == CLOCK_EVT_MODE_ONESHOT)
- disable_mfgpt0_counter();
- break;
-
- case CLOCK_EVT_MODE_ONESHOT:
- /* The oneshot mode have very high deviation, Not use it! */
- break;
-
- case CLOCK_EVT_MODE_RESUME:
- /* Nothing to do here */
- break;
- }
- spin_unlock(&mfgpt_lock);
-}
-
-static struct clock_event_device mfgpt_clockevent = {
- .name = "mfgpt",
- .features = CLOCK_EVT_FEAT_PERIODIC,
- .set_mode = init_mfgpt_timer,
+static struct clock_event_device mfgpt0_clockevent = {
+ .name = "mfgpt0",
+ .features = CLOCK_EVT_MODE_ONESHOT | CLOCK_EVT_FEAT_PERIODIC,
+ .set_mode = mfgpt0_set_mode,
+ .set_next_event = mfgpt0_next_event,
+ .rating = 220,
.irq = CS5536_MFGPT_INTR,
};
-static irqreturn_t timer_interrupt(int irq, void *dev_id)
+static struct irqaction irq5 = {
+ .handler = mfgpt0_interrupt,
+ .flags = IRQF_DISABLED | IRQF_NOBALANCING | IRQF_TIMER,
+ .name = "mfgpt0-timer"
+};
+
+static struct clocksource mfgpt1_clocksource = {
+ .name = "mfgpt1",
+ .rating = 210,
+ .read = mfgpt1_read_cycle,
+ .mask = CLOCKSOURCE_MASK(16),
+ .flags = CLOCK_SOURCE_IS_CONTINUOUS
+};
+
+static inline void enable_mfgpt0_counter(void)
{
u32 basehi;
-
- /*
- * get MFGPT base address
- *
- * NOTE: do not remove me, it's need for the value of mfgpt_base is
- * variable
- */
_rdmsr(DIVIL_MSR_REG(DIVIL_LBAR_MFGPT), &basehi, &mfgpt_base);
- /* ack */
- outw(inw(MFGPT0_SETUP) | 0x4000, MFGPT0_SETUP);
-
- mfgpt_clockevent.event_handler(&mfgpt_clockevent);
-
- return IRQ_HANDLED;
+ /* clockevent: 14M, divisor = 8 (scale=3), CMP2 event mode */
+ outw(MFGPT_SETUP_ACK | MFGPT_SETUP_CMP2EVT |
+ MFGPT_SETUP_CLOCK(1) | MFGPT_SETUP_SCALE(3), MFGPT0_SETUP);
+ outw(0, MFGPT0_CNT);
+ outw(MFGPT_COMPARE(1, 3), MFGPT0_CMP2);
+ outw(0xFFFF, MFGPT0_SETUP);
}
-static struct irqaction irq5 = {
- .handler = timer_interrupt,
- .flags = IRQF_DISABLED | IRQF_NOBALANCING | IRQF_TIMER,
- .name = "timer"
-};
+static inline void enable_mfgpt1_counter(void)
+{
+ u32 basehi;
+ _rdmsr(DIVIL_MSR_REG(DIVIL_LBAR_MFGPT), &basehi, &mfgpt_base);
+
+ /* clocksource: 32K w/ divisor = 2 (scale=1) */
+ outw(MFGPT_SETUP_ACK | MFGPT_SETUP_CLOCK(0) |
+ MFGPT_SETUP_SCALE(1), MFGPT1_SETUP);
+
+ outw(0, MFGPT1_CNT);
+ outw(0xFFFF, MFGPT1_CMP2); /* CNT won't tick with no CMP set */
+ outw(0xFFFF, MFGPT1_SETUP);
+}
+
+void enable_mfgpt_counter(void)
+{
+ /* TODO: add a mfgpt system hard reset here
+ * timers might not reset correctly when OS crashes
+ */
+
+ enable_mfgpt0_counter();
+ enable_mfgpt1_counter();
+}
+EXPORT_SYMBOL(enable_mfgpt_counter);
+
+void disable_mfgpt_counter(void)
+{
+ outw(0x7FFF, MFGPT0_SETUP);
+ outw(0x7FFF, MFGPT1_SETUP);
+}
+EXPORT_SYMBOL(disable_mfgpt_counter);
+
+static void mfgpt0_start_timer(u16 delta)
+{
+ outw(0x7FFF, MFGPT0_SETUP);
+ outw(0, MFGPT0_CNT);
+ outw(delta, MFGPT0_CMP2);
+ outw(0xFFFF, MFGPT0_SETUP);
+}
+
+static void mfgpt0_set_mode(enum clock_event_mode mode,
+ struct clock_event_device *evt)
+{
+ outw(0x7FFF, MFGPT0_SETUP);
+ if (mode == CLOCK_EVT_MODE_PERIODIC)
+ mfgpt0_start_timer(MFGPT_COMPARE(1, 3));
+
+ mfgpt0_mode = mode;
+}
+
+static int mfgpt0_next_event(unsigned long delta,
+ struct clock_event_device *evt)
+{
+ mfgpt0_start_timer(delta);
+ return 0;
+}
+
+static irqreturn_t mfgpt0_interrupt(int irq, void *dev_id)
+{
+ u32 basehi;
+ _rdmsr(DIVIL_MSR_REG(DIVIL_LBAR_MFGPT), &basehi, &mfgpt_base);
+
+ /* stop the timer and ack the interrupt */
+ outw(0x7FFF, MFGPT0_SETUP);
+
+ if (mfgpt0_mode == CLOCK_EVT_MODE_SHUTDOWN)
+ return IRQ_HANDLED;
+
+ /* restart timer for periodic mode */
+ if (mfgpt0_mode == CLOCK_EVT_MODE_PERIODIC)
+ outw(0xFFFF, MFGPT0_SETUP);
+
+ mfgpt0_clockevent.event_handler(&mfgpt0_clockevent);
+ return IRQ_HANDLED;
+}
/*
* Initialize the conversion factor and the min/max deltas of the clock event
@@ -121,14 +171,15 @@
*/
void __init setup_mfgpt0_timer(void)
{
- u32 basehi;
- struct clock_event_device *cd = &mfgpt_clockevent;
+ struct clock_event_device *cd = &mfgpt0_clockevent;
unsigned int cpu = smp_processor_id();
-
cd->cpumask = cpumask_of(cpu);
- clockevent_set_clock(cd, MFGPT_TICK_RATE);
- cd->max_delta_ns = clockevent_delta2ns(0xffff, cd);
- cd->min_delta_ns = clockevent_delta2ns(0xf, cd);
+
+ cd->shift = 22;
+ cd->mult = div_sc(MFGPT_TICK_RATE(1, 3), NSEC_PER_SEC, cd->shift);
+
+ cd->min_delta_ns = clockevent_delta2ns(0xF, cd);
+ cd->max_delta_ns = clockevent_delta2ns(0xFFFF, cd);
/* Enable MFGPT0 Comparator 2 Output to the Interrupt Mapper */
_wrmsr(DIVIL_MSR_REG(MFGPT_IRQ), 0, 0x100);
@@ -136,79 +187,24 @@
/* Enable Interrupt Gate 5 */
_wrmsr(DIVIL_MSR_REG(PIC_ZSEL_LOW), 0, 0x50000);
- /* get MFGPT base address */
- _rdmsr(DIVIL_MSR_REG(DIVIL_LBAR_MFGPT), &basehi, &mfgpt_base);
-
+ enable_mfgpt0_counter();
clockevents_register_device(cd);
-
setup_irq(CS5536_MFGPT_INTR, &irq5);
}
-/*
- * Since the MFGPT overflows every tick, its not very useful
- * to just read by itself. So use jiffies to emulate a free
- * running counter:
- */
-static cycle_t mfgpt_read(struct clocksource *cs)
+static cycle_t mfgpt1_read_cycle(struct clocksource *cs)
{
- unsigned long flags;
- int count;
- u32 jifs;
- static int old_count;
- static u32 old_jifs;
-
- spin_lock_irqsave(&mfgpt_lock, flags);
- /*
- * Although our caller may have the read side of xtime_lock,
- * this is now a seqlock, and we are cheating in this routine
- * by having side effects on state that we cannot undo if
- * there is a collision on the seqlock and our caller has to
- * retry. (Namely, old_jifs and old_count.) So we must treat
- * jiffies as volatile despite the lock. We read jiffies
- * before latching the timer count to guarantee that although
- * the jiffies value might be older than the count (that is,
- * the counter may underflow between the last point where
- * jiffies was incremented and the point where we latch the
- * count), it cannot be newer.
- */
- jifs = jiffies;
- /* read the count */
- count = inw(MFGPT0_CNT);
-
- /*
- * It's possible for count to appear to go the wrong way for this
- * reason:
- *
- * The timer counter underflows, but we haven't handled the resulting
- * interrupt and incremented jiffies yet.
- *
- * Previous attempts to handle these cases intelligently were buggy, so
- * we just do the simple thing now.
- */
- if (count < old_count && jifs == old_jifs)
- count = old_count;
-
- old_count = count;
- old_jifs = jifs;
-
- spin_unlock_irqrestore(&mfgpt_lock, flags);
-
- return (cycle_t) (jifs * COMPARE) + count;
+ return inw(MFGPT1_CNT);
}
-static struct clocksource clocksource_mfgpt = {
- .name = "mfgpt",
- .rating = 120, /* Functional for real use, but not desired */
- .read = mfgpt_read,
- .mask = CLOCKSOURCE_MASK(32),
-};
-
-int __init init_mfgpt_clocksource(void)
+int __init init_mfgpt1_clocksource(void)
{
if (num_possible_cpus() > 1) /* MFGPT does not scale! */
return 0;
- return clocksource_register_hz(&clocksource_mfgpt, MFGPT_TICK_RATE);
+ enable_mfgpt1_counter();
+
+ return clocksource_register_hz(&mfgpt1_clocksource, MFGPT_TICK_RATE(0, 1));
}
-arch_initcall(init_mfgpt_clocksource);
+arch_initcall(init_mfgpt1_clocksource);
diff --git a/arch/mips/loongson/common/cs5536/cs5536_ohci.c b/arch/mips/loongson/common/cs5536/cs5536_ohci.c
index bdedf51..bdb43bb 100644
--- a/arch/mips/loongson/common/cs5536/cs5536_ohci.c
+++ b/arch/mips/loongson/common/cs5536/cs5536_ohci.c
@@ -18,7 +18,7 @@
void pci_ohci_write_reg(int reg, u32 value)
{
- u32 hi = 0, lo = value;
+ u32 hi, lo;
switch (reg) {
case PCI_COMMAND:
@@ -73,77 +73,72 @@
u32 pci_ohci_read_reg(int reg)
{
- u32 conf_data = 0;
+ u32 cfg = 0;
u32 hi, lo;
switch (reg) {
case PCI_VENDOR_ID:
- conf_data =
- CFG_PCI_VENDOR_ID(CS5536_OHCI_DEVICE_ID, CS5536_VENDOR_ID);
+ case PCI_SUBSYSTEM_VENDOR_ID:
+ cfg = CFG_PCI_VENDOR_ID(PCI_DEVICE_ID_AMD_CS5536_OHC,
+ PCI_VENDOR_ID_AMD);
break;
case PCI_COMMAND:
_rdmsr(USB_MSR_REG(USB_OHCI), &hi, &lo);
if (hi & PCI_COMMAND_MASTER)
- conf_data |= PCI_COMMAND_MASTER;
+ cfg |= PCI_COMMAND_MASTER;
if (hi & PCI_COMMAND_MEMORY)
- conf_data |= PCI_COMMAND_MEMORY;
+ cfg |= PCI_COMMAND_MEMORY;
break;
case PCI_STATUS:
- conf_data |= PCI_STATUS_66MHZ;
- conf_data |= PCI_STATUS_FAST_BACK;
+ cfg |= PCI_STATUS_66MHZ;
+ cfg |= PCI_STATUS_FAST_BACK;
_rdmsr(SB_MSR_REG(SB_ERROR), &hi, &lo);
if (lo & SB_PARE_ERR_FLAG)
- conf_data |= PCI_STATUS_PARITY;
- conf_data |= PCI_STATUS_DEVSEL_MEDIUM;
+ cfg |= PCI_STATUS_PARITY;
+ cfg |= PCI_STATUS_DEVSEL_MEDIUM;
break;
case PCI_CLASS_REVISION:
_rdmsr(USB_MSR_REG(USB_CAP), &hi, &lo);
- conf_data = lo & 0x000000ff;
- conf_data |= (CS5536_OHCI_CLASS_CODE << 8);
+ cfg = lo & 0x000000ff;
+ cfg |= (CS5536_OHCI_CLASS_CODE << 8);
break;
case PCI_CACHE_LINE_SIZE:
- conf_data =
- CFG_PCI_CACHE_LINE_SIZE(PCI_NORMAL_HEADER_TYPE,
- PCI_NORMAL_LATENCY_TIMER);
+ cfg = CFG_PCI_CACHE_LINE_SIZE(PCI_NORMAL_HEADER_TYPE,
+ PCI_NORMAL_LATENCY_TIMER);
break;
case PCI_BAR0_REG:
_rdmsr(GLCP_MSR_REG(GLCP_SOFT_COM), &hi, &lo);
if (lo & SOFT_BAR_OHCI_FLAG) {
- conf_data = CS5536_OHCI_RANGE |
+ cfg = CS5536_OHCI_RANGE |
PCI_BASE_ADDRESS_SPACE_MEMORY;
lo &= ~SOFT_BAR_OHCI_FLAG;
_wrmsr(GLCP_MSR_REG(GLCP_SOFT_COM), hi, lo);
} else {
_rdmsr(USB_MSR_REG(USB_OHCI), &hi, &lo);
- conf_data = lo & 0xffffff00;
- conf_data &= ~0x0000000f; /* 32bit mem */
+ cfg = lo & 0xffffff00;
+ cfg &= ~0x0000000f; /* 32bit mem */
}
break;
case PCI_CARDBUS_CIS:
- conf_data = PCI_CARDBUS_CIS_POINTER;
- break;
- case PCI_SUBSYSTEM_VENDOR_ID:
- conf_data =
- CFG_PCI_VENDOR_ID(CS5536_OHCI_SUB_ID, CS5536_SUB_VENDOR_ID);
+ cfg = PCI_CARDBUS_CIS_POINTER;
break;
case PCI_ROM_ADDRESS:
- conf_data = PCI_EXPANSION_ROM_BAR;
+ cfg = PCI_EXPANSION_ROM_BAR;
break;
case PCI_CAPABILITY_LIST:
- conf_data = PCI_CAPLIST_USB_POINTER;
+ cfg = PCI_CAPLIST_USB_POINTER;
break;
case PCI_INTERRUPT_LINE:
- conf_data =
- CFG_PCI_INTERRUPT_LINE(PCI_DEFAULT_PIN, CS5536_USB_INTR);
+ cfg = CFG_PCI_INTERRUPT_LINE(PCI_DEFAULT_PIN, CS5536_USB_INTR);
break;
case PCI_OHCI_INT_REG:
_rdmsr(DIVIL_MSR_REG(PIC_YSEL_LOW), &hi, &lo);
if ((lo & 0x00000f00) == CS5536_USB_INTR)
- conf_data = 1;
+ cfg = 1;
break;
default:
break;
}
- return conf_data;
+ return cfg;
}
diff --git a/arch/mips/loongson/common/early_printk.c b/arch/mips/loongson/common/early_printk.c
index a71736f..649b270 100644
--- a/arch/mips/loongson/common/early_printk.c
+++ b/arch/mips/loongson/common/early_printk.c
@@ -10,9 +10,13 @@
* option) any later version.
*/
#include <linux/serial_reg.h>
+#include <linux/module.h>
+#include <asm/bootinfo.h>
#include <loongson.h>
+unsigned long _loongson_uart_base;
+
#define PORT(base, offset) (u8 *)(base + offset)
static inline unsigned int serial_in(unsigned char *base, int offset)
@@ -39,3 +43,29 @@
serial_out(uart_base, UART_TX, c);
}
+
+void __init prom_init_uart_base(void)
+{
+ unsigned long loongson_uart_base;
+
+ switch (mips_machtype) {
+ case MACH_LEMOTE_FL2E:
+ loongson_uart_base = LOONGSON_PCIIO_BASE + 0x3f8;
+ break;
+ case MACH_LEMOTE_FL2F:
+ case MACH_LEMOTE_LL2F:
+ loongson_uart_base = LOONGSON_PCIIO_BASE + 0x2f8;
+ break;
+ case MACH_LEMOTE_ML2F7:
+ case MACH_LEMOTE_YL2F89:
+ case MACH_DEXXON_GDIUM2F10:
+ case MACH_LEMOTE_NAS:
+ default:
+ /* The CPU provided serial port */
+ loongson_uart_base = LOONGSON_LIO1_BASE + 0x3f8;
+ break;
+ }
+
+ _loongson_uart_base =
+ (unsigned long)ioremap_nocache(loongson_uart_base, 8);
+}
diff --git a/arch/mips/loongson/common/env.c b/arch/mips/loongson/common/env.c
index d93830a..d532c83 100644
--- a/arch/mips/loongson/common/env.c
+++ b/arch/mips/loongson/common/env.c
@@ -40,7 +40,6 @@
/* 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 */
@@ -60,8 +59,7 @@
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) {
+ switch (cpu_prid_rev()) {
case PRID_REV_LOONGSON2E:
cpu_clock_freq = 533080000;
break;
diff --git a/arch/mips/loongson/common/gpio.c b/arch/mips/loongson/common/gpio.c
index e8a0ffa..a8645f8 100644
--- a/arch/mips/loongson/common/gpio.c
+++ b/arch/mips/loongson/common/gpio.c
@@ -19,7 +19,6 @@
#include <loongson.h>
#include <linux/gpio.h>
-#define STLS2F_N_GPIO 4
#define STLS2F_GPIO_IN_OFFSET 16
static DEFINE_SPINLOCK(gpio_lock);
@@ -29,7 +28,7 @@
u32 val;
u32 mask;
- if (gpio >= STLS2F_N_GPIO)
+ if (gpio >= ARCH_NR_GPIOS)
return __gpio_get_value(gpio);
mask = 1 << (gpio + STLS2F_GPIO_IN_OFFSET);
@@ -46,7 +45,7 @@
u32 val;
u32 mask;
- if (gpio >= STLS2F_N_GPIO) {
+ if (gpio >= ARCH_NR_GPIOS) {
__gpio_set_value(gpio, state);
return ;
}
@@ -66,7 +65,7 @@
int gpio_cansleep(unsigned gpio)
{
- if (gpio < STLS2F_N_GPIO)
+ if (gpio < ARCH_NR_GPIOS)
return 0;
else
return __gpio_cansleep(gpio);
@@ -78,7 +77,7 @@
u32 temp;
u32 mask;
- if (gpio >= STLS2F_N_GPIO)
+ if (gpio >= ARCH_NR_GPIOS)
return -EINVAL;
spin_lock(&gpio_lock);
@@ -97,7 +96,7 @@
u32 temp;
u32 mask;
- if (gpio >= STLS2F_N_GPIO)
+ if (gpio >= ARCH_NR_GPIOS)
return -EINVAL;
gpio_set_value(gpio, level);
@@ -129,7 +128,7 @@
.direction_output = ls2f_gpio_direction_output,
.set = ls2f_gpio_set_value,
.base = 0,
- .ngpio = STLS2F_N_GPIO,
+ .ngpio = ARCH_NR_GPIOS,
};
static int __init ls2f_gpio_setup(void)
diff --git a/arch/mips/loongson/common/init.c b/arch/mips/loongson/common/init.c
index 19d3415..73f4460 100644
--- a/arch/mips/loongson/common/init.c
+++ b/arch/mips/loongson/common/init.c
@@ -30,8 +30,10 @@
prom_init_env();
prom_init_memory();
+#ifdef CONFIG_EARLY_PRINTK
/*init the uart base address */
prom_init_uart_base();
+#endif
}
void __init prom_free_prom_memory(void)
diff --git a/arch/mips/loongson/common/irq.c b/arch/mips/loongson/common/irq.c
index 5897471..30396c8 100644
--- a/arch/mips/loongson/common/irq.c
+++ b/arch/mips/loongson/common/irq.c
@@ -10,6 +10,10 @@
#include <linux/delay.h>
#include <linux/interrupt.h>
+#include <asm/irq_cpu.h>
+#include <asm/i8259.h>
+#include <asm/mipsregs.h>
+
#include <loongson.h>
/*
* the first level int-handler will jump here if it is a bonito irq
@@ -48,20 +52,32 @@
void __init arch_init_irq(void)
{
/*
- * Clear all of the interrupts while we change the able around a bit.
- * int-handler is not on bootstrap
+ * The vector addresses of the generic exceptions are in the cached
+ * address space.
*/
- clear_c0_status(ST0_IM | ST0_BEV);
+ clear_c0_status(ST0_BEV);
- /* no steer */
+ /* No steer */
LOONGSON_INTSTEER = 0;
/*
- * Mask out all interrupt by writing "1" to all bit position in
- * the interrupt reset reg.
+ * Clear all interrupts
*/
LOONGSON_INTENCLR = ~0;
+ /*
+ * Sets the first-level interrupt dispatcher:
+ *
+ * 0-15: i8259 interrupt (If CONFIG_I8259 selected)
+ * 16-23: mips cpu interrupt
+ * 32-63: bonito irq
+ */
+ mips_cpu_irq_init();
+ bonito_irq_init();
+#ifdef CONFIG_I8259
+ init_i8259_irqs();
+#endif
+
/* machine specific irq init */
mach_init_irq();
}
diff --git a/arch/mips/loongson/common/mem.c b/arch/mips/loongson/common/mem.c
index 30eba60..e90f2de 100644
--- a/arch/mips/loongson/common/mem.c
+++ b/arch/mips/loongson/common/mem.c
@@ -14,39 +14,24 @@
#include <mem.h>
#include <pci.h>
+#define MB(x) ((x) << 20)
+
void __init prom_init_memory(void)
{
- 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(0x0, MB(memsize), BOOT_MEM_RAM);
+ add_memory_region(MB(memsize), LOONGSON_PCI_MEM_START - MB(memsize), BOOT_MEM_RESERVED);
#ifdef CONFIG_CPU_SUPPORTS_ADDRWINCFG
- {
- int bit;
-
- bit = fls(memsize + highmemsize);
- if (bit != ffs(memsize + highmemsize))
- bit += 20;
- else
- bit = bit + 20 - 1;
-
- /* set cpu window3 to map CPU to DDR: 2G -> 2G */
- LOONGSON_ADDRWIN_CPUTODDR(ADDRWIN_WIN3, 0x80000000ul,
- 0x80000000ul, (1 << bit));
- mmiowb();
- }
-#endif /* !CONFIG_CPU_SUPPORTS_ADDRWINCFG */
+ /* set cpu window3 to map CPU to DDR: 2G -> 0G */
+ LOONGSON_ADDRWIN_CPUTODDR(ADDRWIN_WIN3, 0x80000000ul, 0, MB(memsize + highmemsize));
+ mmiowb();
+#endif
#ifdef CONFIG_64BIT
if (highmemsize > 0)
- add_memory_region(LOONGSON_HIGHMEM_START,
- highmemsize << 20, BOOT_MEM_RAM);
-
+ add_memory_region(LOONGSON_HIGHMEM_START, MB(highmemsize), BOOT_MEM_RAM);
add_memory_region(LOONGSON_PCI_MEM_END + 1, LOONGSON_HIGHMEM_START -
- LOONGSON_PCI_MEM_END - 1, BOOT_MEM_RESERVED);
-
-#endif /* !CONFIG_64BIT */
+ LOONGSON_PCI_MEM_END - 1, BOOT_MEM_RESERVED);
+#endif
}
/* override of arch/mips/mm/cache.c: __uncached_access */
diff --git a/arch/mips/loongson/common/mtd.c b/arch/mips/loongson/common/mtd.c
new file mode 100644
index 0000000..49a57a7
--- /dev/null
+++ b/arch/mips/loongson/common/mtd.c
@@ -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 --git a/arch/mips/loongson/common/pci.c b/arch/mips/loongson/common/pci.c
index 31d8c5e..5077456 100644
--- a/arch/mips/loongson/common/pci.c
+++ b/arch/mips/loongson/common/pci.c
@@ -50,11 +50,11 @@
LOONGSON_PCIMAP_WIN(0, 0);
/*
- * PCI-DMA to local mapping: [2G,2G+256M] -> [0M,256M]
+ * PCI-DMA to local mapping: [2G,4G] -> [0M,2G]
*/
LOONGSON_PCIBASE0 = 0x80000000ul; /* base: 2G -> mmap: 0M */
- /* size: 256M, burst transmission, pre-fetch enable, 64bit */
- LOONGSON_PCI_HIT0_SEL_L = 0xc000000cul;
+ /* size: 2G, burst transmission, pre-fetch enable, 64bit */
+ LOONGSON_PCI_HIT0_SEL_L = 0x8000000cul;
LOONGSON_PCI_HIT0_SEL_H = 0xfffffffful;
LOONGSON_PCI_HIT1_SEL_L = 0x00000006ul; /* set this BAR as invalid */
LOONGSON_PCI_HIT1_SEL_H = 0x00000000ul;
diff --git a/arch/mips/loongson/common/platform.c b/arch/mips/loongson/common/platform.c
index ed007a2..4b97404 100644
--- a/arch/mips/loongson/common/platform.c
+++ b/arch/mips/loongson/common/platform.c
@@ -12,16 +12,14 @@
#include <linux/platform_device.h>
static struct platform_device loongson2_cpufreq_device = {
- .name = "loongson2_cpufreq",
+ .name = "l2_cpufreq",
.id = -1,
};
static int __init loongson2_cpufreq_init(void)
{
- struct cpuinfo_mips *c = ¤t_cpu_data;
-
/* Only 2F revision and it's successors support CPUFreq */
- if ((c->processor_id & PRID_REV_MASK) >= PRID_REV_LOONGSON2F)
+ if (cpu_prid_rev() >= PRID_REV_LOONGSON2F)
return platform_device_register(&loongson2_cpufreq_device);
return -ENODEV;
diff --git a/arch/mips/loongson/common/serial.c b/arch/mips/loongson/common/serial.c
index 7580873..8f2ebf4 100644
--- a/arch/mips/loongson/common/serial.c
+++ b/arch/mips/loongson/common/serial.c
@@ -19,58 +19,44 @@
#include <loongson.h>
#include <machine.h>
-#define PORT(int) \
+#define PORT(int, base_baud, io_type, port) \
{ \
.irq = int, \
- .uartclk = 1843200, \
- .iotype = UPIO_PORT, \
+ .uartclk = base_baud, \
+ .iotype = io_type, \
.flags = UPF_BOOT_AUTOCONF | UPF_SKIP_TEST, \
.regshift = 0, \
+ .iobase = port, \
}
-#define PORT_M(int) \
-{ \
- .irq = MIPS_CPU_IRQ_BASE + (int), \
- .uartclk = 3686400, \
- .iotype = UPIO_MEM, \
- .membase = (void __iomem *)NULL, \
- .flags = UPF_BOOT_AUTOCONF | UPF_SKIP_TEST, \
- .regshift = 0, \
-}
-
-static struct plat_serial8250_port uart8250_data[][2] = {
- [MACH_LOONGSON_UNKNOWN] {},
- [MACH_LEMOTE_FL2E] {PORT(4), {} },
- [MACH_LEMOTE_FL2F] {PORT(3), {} },
- [MACH_LEMOTE_ML2F7] {PORT_M(3), {} },
- [MACH_LEMOTE_YL2F89] {PORT_M(3), {} },
- [MACH_DEXXON_GDIUM2F10] {PORT_M(3), {} },
- [MACH_LEMOTE_NAS] {PORT_M(3), {} },
- [MACH_LEMOTE_LL2F] {PORT(3), {} },
- [MACH_LOONGSON_END] {},
+static struct plat_serial8250_port uart8250_data[] = {
+ /* ttyS0: cpu_uart0 Yeeloong, Gdium, UNAS, ... */
+ PORT((MIPS_CPU_IRQ_BASE + 3), 3686400, UPIO_MEM, 0x3f8),
+ /* ttyS1: sb_uart1 2E */
+ PORT(4, 1843200, UPIO_PORT, 0x3f8),
+ /* ttyS2: sb_uart2 fuloong2f */
+ PORT(3, 1843200, UPIO_PORT, 0x2f8),
+ {},
};
static struct platform_device uart8250_device = {
.name = "serial8250",
.id = PLAT8250_DEV_PLATFORM,
+ .dev = {
+ .platform_data = uart8250_data,
+ },
};
static int __init serial_init(void)
{
- unsigned char iotype;
+ uart8250_data[0].membase = (void __iomem *)ioremap_nocache(
+ LOONGSON_LIO1_BASE + uart8250_data[0].iobase, 8);
- iotype = uart8250_data[mips_machtype][0].iotype;
-
- if (UPIO_MEM == iotype)
- uart8250_data[mips_machtype][0].membase =
- (void __iomem *)_loongson_uart_base;
- else if (UPIO_PORT == iotype)
- uart8250_data[mips_machtype][0].iobase =
- loongson_uart_base - LOONGSON_PCIIO_BASE;
-
- uart8250_device.dev.platform_data = uart8250_data[mips_machtype];
-
- return platform_device_register(&uart8250_device);
+ platform_device_register(&uart8250_device);
+ return 0;
}
device_initcall(serial_init);
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("liu shiwei <liushiwei@anheng.com.cn>");
+MODULE_DESCRIPTION("loongson serial");
diff --git a/arch/mips/loongson/common/time.c b/arch/mips/loongson/common/time.c
index 9fdd01f..b8cd030 100644
--- a/arch/mips/loongson/common/time.c
+++ b/arch/mips/loongson/common/time.c
@@ -10,6 +10,8 @@
* Free Software Foundation; either version 2 of the License, or (at your
* option) any later version.
*/
+#include <linux/rtc.h>
+
#include <asm/mc146818-time.h>
#include <asm/time.h>
@@ -24,8 +26,81 @@
setup_mfgpt0_timer();
}
+#ifdef CONFIG_LOONGSON_MC146818
void read_persistent_clock(struct timespec *ts)
{
ts->tv_sec = mc146818_get_cmos_time();
ts->tv_nsec = 0;
}
+#else
+
+/* If no CMOS RTC, use the one below */
+
+/*
+ * Cloned from drivers/rtc/hctosys.c
+ *
+ * If CONFIG_RTC_HCTOSYS=y is enabled, the system time can be set from the
+ * hardware clock(when boot and resuming from suspend), this may be also done
+ * (duplicately) by the timekeeper, which may need to be avoided(TODO).
+ *
+ * read_persistent_clock() may be useful in some places, e.g. there is not
+ * peristent clock in the system, we can use this to recover the system time.
+ *
+ * Note: The device indicated by CONFIG_RTC_HCTOSYS_DEVICE must be the one
+ * created by the RTC driver. Use Gdium as an example, We must disable the
+ * rt_cmos driver If we want to use the rtc_m41t80 driver for
+ * CONFIG_RTC_HCTOSYS_DEVICE is configured as /dev/rtc0, if rtc_cmos is
+ * enabled, rtc_cmos driver will be used, but it is not supported by Gdium.
+ * So, for Gdium, please ensure "# CONFIG_RTC_DRV_CMOS is not set"
+ */
+
+#ifdef CONFIG_RTC_HCTOSYS
+void read_persistent_clock(struct timespec *ts)
+{
+ int err = -ENODEV;
+ struct rtc_time tm;
+ struct rtc_device *rtc;
+
+ /* We can not access the RTC device before it is initialized ... */
+ if (rtc_hctosys_ret != 0) {
+ ts->tv_sec = 0;
+ ts->tv_nsec = 0;
+ return;
+ }
+
+ rtc = rtc_class_open(CONFIG_RTC_HCTOSYS_DEVICE);
+
+ if (rtc == NULL) {
+ pr_err("%s: unable to open rtc device (%s)\n",
+ __FILE__, CONFIG_RTC_HCTOSYS_DEVICE);
+ goto err_open;
+ }
+
+ err = rtc_read_time(rtc, &tm);
+ if (err) {
+ dev_err(rtc->dev.parent,
+ "hctosys: unable to read the hardware clock\n");
+ goto err_read;
+
+ }
+
+ err = rtc_valid_tm(&tm);
+ if (err) {
+ dev_err(rtc->dev.parent,
+ "hctosys: invalid date/time\n");
+ goto err_invalid;
+ }
+
+ ts->tv_nsec = NSEC_PER_SEC >> 1,
+ rtc_tm_to_time(&tm, &ts->tv_sec);
+
+err_invalid:
+err_read:
+ rtc_class_close(rtc);
+
+err_open:
+ rtc_hctosys_ret = err;
+}
+#endif /* CONFIG_RTC_HCTOSYS */
+
+#endif /* !CONFIG_LOONGSON_MC146818 */
diff --git a/arch/mips/loongson/common/uart_base.c b/arch/mips/loongson/common/uart_base.c
deleted file mode 100644
index d69ea54..0000000
--- a/arch/mips/loongson/common/uart_base.c
+++ /dev/null
@@ -1,45 +0,0 @@
-/*
- * 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/module.h>
-#include <asm/bootinfo.h>
-
-#include <loongson.h>
-
-/* ioremapped */
-unsigned long _loongson_uart_base;
-EXPORT_SYMBOL(_loongson_uart_base);
-/* raw */
-unsigned long loongson_uart_base;
-EXPORT_SYMBOL(loongson_uart_base);
-
-void prom_init_loongson_uart_base(void)
-{
- switch (mips_machtype) {
- case MACH_LEMOTE_FL2E:
- loongson_uart_base = LOONGSON_PCIIO_BASE + 0x3f8;
- break;
- case MACH_LEMOTE_FL2F:
- case MACH_LEMOTE_LL2F:
- loongson_uart_base = LOONGSON_PCIIO_BASE + 0x2f8;
- break;
- case MACH_LEMOTE_ML2F7:
- case MACH_LEMOTE_YL2F89:
- case MACH_DEXXON_GDIUM2F10:
- case MACH_LEMOTE_NAS:
- default:
- /* The CPU provided serial port */
- loongson_uart_base = LOONGSON_LIO1_BASE + 0x3f8;
- break;
- }
-
- _loongson_uart_base =
- (unsigned long)ioremap_nocache(loongson_uart_base, 8);
-}
diff --git a/arch/mips/loongson/fuloong-2e/irq.c b/arch/mips/loongson/fuloong-2e/irq.c
index 3cf1fef..560a065 100644
--- a/arch/mips/loongson/fuloong-2e/irq.c
+++ b/arch/mips/loongson/fuloong-2e/irq.c
@@ -9,7 +9,6 @@
*/
#include <linux/interrupt.h>
-#include <asm/irq_cpu.h>
#include <asm/i8259.h>
#include <loongson.h>
@@ -47,21 +46,10 @@
void __init mach_init_irq(void)
{
- /* init all controller
- * 0-15 ------> i8259 interrupt
- * 16-23 ------> mips cpu interrupt
- * 32-63 ------> bonito irq
- */
-
/* most bonito irq should be level triggered */
LOONGSON_INTEDGE = LOONGSON_ICU_SYSTEMERR | LOONGSON_ICU_MASTERERR |
LOONGSON_ICU_RETRYERR | LOONGSON_ICU_MBOXES;
- /* Sets the first-level interrupt dispatcher. */
- mips_cpu_irq_init();
- init_i8259_irqs();
- bonito_irq_init();
-
/* bonito irq at IP2 */
setup_irq(MIPS_CPU_IRQ_BASE + 2, &cascade_irqaction);
/* 8259 irq at IP5 */
diff --git a/arch/mips/loongson/gdium/Makefile b/arch/mips/loongson/gdium/Makefile
new file mode 100644
index 0000000..f3f4f51
--- /dev/null
+++ b/arch/mips/loongson/gdium/Makefile
@@ -0,0 +1,6 @@
+# Makefile for gdium
+
+obj-y += irq.o reset.o platform.o
+
+obj-$(CONFIG_MFD_SM501) += sm501-pwm.o
+obj-$(CONFIG_GDIUM_PWM_CLOCK) += gdium-clock.o
diff --git a/arch/mips/loongson/gdium/gdium-clock.c b/arch/mips/loongson/gdium/gdium-clock.c
new file mode 100644
index 0000000..fdbf42a
--- /dev/null
+++ b/arch/mips/loongson/gdium/gdium-clock.c
@@ -0,0 +1,234 @@
+/*
+ * Doesn't work really well. When used, the clocksource is producing
+ * bad timings and the clockevent can't be used (don't have one shot feature
+ * thus can't switch on the fly and the pwm is initialised too late to be able
+ * to use it at boot time).
+ */
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/platform_device.h>
+#include <linux/interrupt.h>
+#include <linux/delay.h>
+#include <linux/pwm.h>
+#include <linux/clocksource.h>
+#include <linux/debugfs.h>
+#include <asm/irq_cpu.h>
+#include <asm/mipsregs.h>
+#include <asm/mips-boards/bonito64.h>
+#include <asm/time.h>
+
+#include <loongson.h>
+
+#define CLOCK_PWM 1
+#define CLOCK_PWM_FREQ 1500000 /* Freq in Hz */
+#define CLOCK_LATCH ((CLOCK_PWM_FREQ + HZ/2) / HZ)
+#define CLOCK_PWM_PERIOD (1000000000/CLOCK_PWM_FREQ) /* period ns */
+#define CLOCK_PWM_DUTY 50
+#define CLOCK_PWM_IRQ (MIPS_CPU_IRQ_BASE + 4)
+
+static const char drv_name[] = "gdium-clock";
+
+static struct pwm_device *clock_pwm;
+
+static DEFINE_SPINLOCK(clock_pwm_lock);
+static uint64_t clock_tick;
+
+static irqreturn_t gdium_pwm_clock_interrupt(int irq, void *dev_id)
+{
+ struct clock_event_device *cd = dev_id;
+ unsigned long flag;
+
+ spin_lock_irqsave(&clock_pwm_lock, flag);
+ clock_tick++;
+ /* wait intn2 to finish */
+ do {
+ LOONGSON_INTENCLR = (1 << 13);
+ } while (LOONGSON_INTISR & (1 << 13));
+ spin_unlock_irqrestore(&clock_pwm_lock, flag);
+
+ if (cd && cd->event_handler)
+ cd->event_handler(cd);
+
+ return IRQ_HANDLED;
+}
+
+static cycle_t gdium_pwm_clock_read(struct clocksource *cs)
+{
+ unsigned long flag;
+ uint32_t jifs;
+ uint64_t ticks;
+
+ spin_lock_irqsave(&clock_pwm_lock, flag);
+ jifs = jiffies;
+ ticks = clock_tick;
+ spin_unlock_irqrestore(&clock_pwm_lock, flag);
+ /* return (cycle_t)ticks; */
+ return (cycle_t)(CLOCK_LATCH * jifs);
+}
+
+static struct clocksource gdium_pwm_clock_clocksource = {
+ .name = "gdium_csrc",
+ .read = gdium_pwm_clock_read,
+ .mask = CLOCKSOURCE_MASK(64),
+ .flags = CLOCK_SOURCE_IS_CONTINUOUS | CLOCK_SOURCE_MUST_VERIFY,
+ .shift = 20,
+};
+
+/* Debug fs */
+static int gdium_pwm_clock_show(struct seq_file *s, void *p)
+{
+ unsigned long flag;
+ uint64_t ticks;
+
+ spin_lock_irqsave(&clock_pwm_lock, flag);
+ ticks = clock_tick;
+ spin_unlock_irqrestore(&clock_pwm_lock, flag);
+ seq_printf(s, "%lld\n", ticks);
+ return 0;
+}
+
+static int gdium_pwm_clock_open(struct inode *inode, struct file *file)
+{
+ return single_open(file, gdium_pwm_clock_show, inode->i_private);
+}
+
+static const struct file_operations gdium_pwm_clock_fops = {
+ .open = gdium_pwm_clock_open,
+ .read = seq_read,
+ .llseek = seq_lseek,
+ .release = single_release,
+ .owner = THIS_MODULE,
+};
+static struct dentry *debugfs_file;
+
+static void gdium_pwm_clock_set_mode(enum clock_event_mode mode,
+ struct clock_event_device *evt)
+{
+ /* Nothing to do ... */
+}
+
+static struct clock_event_device gdium_pwm_clock_cevt = {
+ .name = "gdium_cevt",
+ .features = CLOCK_EVT_FEAT_PERIODIC,
+ /* .mult, .shift, .max_delta_ns and .min_delta_ns left uninitialized */
+ .rating = 299,
+ .irq = CLOCK_PWM_IRQ,
+ .set_mode = gdium_pwm_clock_set_mode,
+};
+
+static struct platform_device_id platform_device_ids[] = {
+ {
+ .name = "gdium-pwmclk",
+ },
+ {}
+};
+MODULE_DEVICE_TABLE(platform, platform_device_ids);
+
+static struct platform_driver gdium_pwm_clock_driver = {
+ .driver = {
+ .name = drv_name,
+ .owner = THIS_MODULE,
+ },
+ .id_table = platform_device_ids,
+};
+
+static int gdium_pwm_clock_drvinit(void)
+{
+ int ret;
+ struct clocksource *cs = &gdium_pwm_clock_clocksource;
+ struct clock_event_device *cd = &gdium_pwm_clock_cevt;
+ unsigned int cpu = smp_processor_id();
+
+ clock_tick = 0;
+
+ clock_pwm = pwm_request(CLOCK_PWM, drv_name);
+ if (clock_pwm == NULL) {
+ pr_err("unable to request PWM for Gdium clock\n");
+ return -EBUSY;
+ }
+ ret = pwm_config(clock_pwm, CLOCK_PWM_DUTY, CLOCK_PWM_PERIOD);
+ if (ret) {
+ pr_err("unable to configure PWM for Gdium clock\n");
+ goto err_pwm_request;
+ }
+ ret = pwm_enable(clock_pwm);
+ if (ret) {
+ pr_err("unable to enable PWM for Gdium clock\n");
+ goto err_pwm_request;
+ }
+
+ cd->cpumask = cpumask_of(cpu);
+
+ cd->shift = 22;
+ cd->mult = div_sc(CLOCK_PWM_FREQ, NSEC_PER_SEC, cd->shift);
+ cd->max_delta_ns = clockevent_delta2ns(0x7FFF, cd);
+ cd->min_delta_ns = clockevent_delta2ns(0xF, cd);
+ clockevents_register_device(&gdium_pwm_clock_cevt);
+
+ /* SM501 PWM1 connected to intn2 <->ip4 */
+ LOONGSON_INTPOL = (1 << 13);
+ LOONGSON_INTEDGE &= ~(1 << 13);
+ ret = request_irq(CLOCK_PWM_IRQ, gdium_pwm_clock_interrupt, IRQF_DISABLED, drv_name, &gdium_pwm_clock_cevt);
+ if (ret) {
+ pr_err("Can't claim irq\n");
+ goto err_pwm_disable;
+ }
+
+ cs->rating = 200;
+ cs->mult = clocksource_hz2mult(CLOCK_PWM_FREQ, cs->shift);
+ ret = clocksource_register(&gdium_pwm_clock_clocksource);
+ if (ret) {
+ pr_err("Can't register clocksource\n");
+ goto err_irq;
+ }
+ pr_info("Clocksource registered with shift %d and mult %d\n",
+ cs->shift, cs->mult);
+
+ debugfs_file = debugfs_create_file(drv_name, S_IFREG | S_IRUGO,
+ NULL, NULL, &gdium_pwm_clock_fops);
+
+ return 0;
+
+err_irq:
+ free_irq(CLOCK_PWM_IRQ, &gdium_pwm_clock_cevt);
+err_pwm_disable:
+ pwm_disable(clock_pwm);
+err_pwm_request:
+ pwm_free(clock_pwm);
+ return ret;
+}
+
+static void gdium_pwm_clock_drvexit(void)
+{
+ free_irq(CLOCK_PWM_IRQ, &gdium_pwm_clock_cevt);
+ pwm_disable(clock_pwm);
+ pwm_free(clock_pwm);
+}
+
+
+static int __devinit gdium_pwm_clock_init(void)
+{
+ int ret = gdium_pwm_clock_drvinit();
+
+ if (ret) {
+ pr_err("Fail to register gdium clock driver\n");
+ return ret;
+ }
+
+ return platform_driver_register(&gdium_pwm_clock_driver);
+}
+
+static void __exit gdium_pwm_clock_cleanup(void)
+{
+ gdium_pwm_clock_drvexit();
+ platform_driver_unregister(&gdium_pwm_clock_driver);
+}
+
+module_init(gdium_pwm_clock_init);
+module_exit(gdium_pwm_clock_cleanup);
+
+MODULE_AUTHOR("Arnaud Patard <apatard@mandriva.com>");
+MODULE_DESCRIPTION("Gdium PWM clock driver");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:gdium-pwmclk");
diff --git a/arch/mips/loongson/gdium/irq.c b/arch/mips/loongson/gdium/irq.c
new file mode 100644
index 0000000..2415d20
--- /dev/null
+++ b/arch/mips/loongson/gdium/irq.c
@@ -0,0 +1,55 @@
+/*
+ * Copyright (C) 2007 Lemote Inc.
+ * Author: Fuxin Zhang, zhangfx@lemote.com
+ *
+ * Copyright (c) 2010 yajin <yajin@vm-kernel.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/interrupt.h>
+#include <linux/module.h>
+
+#include <loongson.h>
+#include <machine.h>
+
+#define LOONGSON_TIMER_IRQ (MIPS_CPU_IRQ_BASE + 7) /* cpu timer */
+#define LOONGSON_NORTH_BRIDGE_IRQ (MIPS_CPU_IRQ_BASE + 6) /* bonito */
+#define LOONGSON_UART_IRQ (MIPS_CPU_IRQ_BASE + 3) /* cpu serial port */
+
+void mach_irq_dispatch(unsigned int pending)
+{
+ if (pending & CAUSEF_IP7)
+ do_IRQ(LOONGSON_TIMER_IRQ);
+ else if (pending & CAUSEF_IP6) { /* North Bridge, Perf counter */
+ do_perfcnt_IRQ();
+ bonito_irqdispatch();
+ } else if (pending & CAUSEF_IP3) /* CPU UART */
+ do_IRQ(LOONGSON_UART_IRQ);
+#if defined(CONFIG_GDIUM_PWM_CLOCK) || defined(CONFIG_GDIUM_PWM_CLOCK_MODULE)
+ else if (pending & CAUSEF_IP4) /* SM501 PWM clock */
+ do_IRQ(MIPS_CPU_IRQ_BASE + 4);
+#endif
+ else
+ spurious_interrupt();
+}
+
+static irqreturn_t ip6_action(int cpl, void *dev_id)
+{
+ return IRQ_HANDLED;
+}
+
+struct irqaction ip6_irqaction = {
+ .handler = ip6_action,
+ .name = "cascade",
+ .flags = IRQF_SHARED,
+};
+
+void __init mach_init_irq(void)
+{
+ /* setup north bridge irq (bonito) */
+ setup_irq(LOONGSON_NORTH_BRIDGE_IRQ, &ip6_irqaction);
+}
diff --git a/arch/mips/loongson/gdium/platform.c b/arch/mips/loongson/gdium/platform.c
new file mode 100644
index 0000000..ffafba4
--- /dev/null
+++ b/arch/mips/loongson/gdium/platform.c
@@ -0,0 +1,135 @@
+/*
+ * Copyright (c) 2009 Philippe Vachon <philippe@cowpig.ca>
+ *
+ * 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/kernel.h>
+#include <linux/platform_device.h>
+#include <linux/pwm_backlight.h>
+#include <linux/i2c.h>
+#include <linux/i2c-gpio.h>
+
+#define GDIUM_GPIO_BASE 224
+
+static struct i2c_board_info __initdata sm502dev_i2c_devices[] = {
+ {
+ I2C_BOARD_INFO("lm75", 0x48),
+ },
+ {
+ I2C_BOARD_INFO("m41t83", 0x68),
+ },
+ {
+ I2C_BOARD_INFO("gdium-laptop", 0x40),
+ },
+};
+
+static int sm502dev_backlight_init(struct device *dev)
+{
+ /* Add gpio request stuff here */
+ return 0;
+}
+
+static void sm502dev_backlight_exit(struct device *dev)
+{
+ /* Add gpio free stuff here */
+}
+
+static struct platform_pwm_backlight_data backlight_data = {
+ .pwm_id = 0,
+ .max_brightness = 15,
+ .dft_brightness = 8,
+ .pwm_period_ns = 50000, /* 20 kHz */
+ .init = sm502dev_backlight_init,
+ .exit = sm502dev_backlight_exit,
+};
+
+static struct platform_device backlight = {
+ .name = "pwm-backlight",
+ .dev = {
+ .platform_data = &backlight_data,
+ },
+ .id = -1,
+};
+
+/*
+ * Warning this stunt is very dangerous
+ * as the sm501 gpio have dynamic numbers...
+ */
+/* bus 0 is the one for the ST7, DS75 etc... */
+static struct i2c_gpio_platform_data i2c_gpio0_data = {
+#if CONFIG_GDIUM_VERSION > 2
+ .sda_pin = GDIUM_GPIO_BASE + 13,
+ .scl_pin = GDIUM_GPIO_BASE + 6,
+#else
+ .sda_pin = 192+15,
+ .scl_pin = 192+14,
+#endif
+ .udelay = 5,
+ .timeout = HZ / 10,
+ .sda_is_open_drain = 0,
+ .scl_is_open_drain = 0,
+};
+
+static struct platform_device i2c_gpio0_device = {
+ .name = "i2c-gpio",
+ .id = 0,
+ .dev = { .platform_data = &i2c_gpio0_data, },
+};
+
+/* bus 1 is for the CRT/VGA external screen */
+static struct i2c_gpio_platform_data i2c_gpio1_data = {
+ .sda_pin = GDIUM_GPIO_BASE + 10,
+ .scl_pin = GDIUM_GPIO_BASE + 9,
+ .udelay = 5,
+ .timeout = HZ / 10,
+ .sda_is_open_drain = 0,
+ .scl_is_open_drain = 0,
+};
+
+static struct platform_device i2c_gpio1_device = {
+ .name = "i2c-gpio",
+ .id = 1,
+ .dev = { .platform_data = &i2c_gpio1_data, },
+};
+
+static struct platform_device gdium_clock = {
+ .name = "gdium-pwmclk",
+ .id = -1,
+};
+
+static struct platform_device *devices[] __initdata = {
+ &i2c_gpio0_device,
+ &i2c_gpio1_device,
+ &backlight,
+ &gdium_clock,
+};
+
+static int __init gdium_platform_devices_setup(void)
+{
+ int ret;
+
+ pr_info("Registering gdium platform devices\n");
+
+ ret = i2c_register_board_info(0, sm502dev_i2c_devices,
+ ARRAY_SIZE(sm502dev_i2c_devices));
+
+ if (ret != 0) {
+ pr_info("Error while registering platform devices: %d\n", ret);
+ return ret;
+ }
+
+ platform_add_devices(devices, ARRAY_SIZE(devices));
+
+ return 0;
+}
+
+/*
+ * some devices are on the pwm stuff which is behind the mfd which is
+ * behind the pci bus so arch_initcall can't work because too early
+ */
+late_initcall(gdium_platform_devices_setup);
diff --git a/arch/mips/loongson/gdium/reset.c b/arch/mips/loongson/gdium/reset.c
new file mode 100644
index 0000000..8289f95
--- /dev/null
+++ b/arch/mips/loongson/gdium/reset.c
@@ -0,0 +1,22 @@
+/* Board-specific reboot/shutdown routines
+ *
+ * Copyright (C) 2010 yajin <yajin@vm-kernel.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 <loongson.h>
+
+void mach_prepare_shutdown(void)
+{
+ LOONGSON_GPIOIE &= ~(1<<1);
+ LOONGSON_GPIODATA |= (1<<1);
+}
+
+void mach_prepare_reboot(void)
+{
+ LOONGSON_GPIOIE &= ~(1<<2);
+ LOONGSON_GPIODATA &= ~(1<<2);
+}
diff --git a/arch/mips/loongson/gdium/sm501-pwm.c b/arch/mips/loongson/gdium/sm501-pwm.c
new file mode 100644
index 0000000..5af3b23
--- /dev/null
+++ b/arch/mips/loongson/gdium/sm501-pwm.c
@@ -0,0 +1,465 @@
+/*
+ * SM501 PWM clock
+ * Copyright (C) 2009-2010 Arnaud Patard <apatard@mandriva.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/kernel.h>
+#include <linux/errno.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+#include <linux/pwm.h>
+#include <linux/sm501.h>
+#include <linux/sm501-regs.h>
+#include <linux/debugfs.h>
+#include <linux/seq_file.h>
+
+static const char drv_name[] = "sm501-pwm";
+
+#define INPUT_CLOCK 96 /* MHz */
+#define PWM_COUNT 3
+
+#define SM501PWM_HIGH_COUNTER (1<<20)
+#define SM501PWM_LOW_COUNTER (1<<8)
+#define SM501PWM_CLOCK_DIVIDE (1>>4)
+#define SM501PWM_IP (1<<3)
+#define SM501PWM_I (1<<2)
+#define SM501PWM_E (1<<0)
+
+struct pwm_device {
+ struct list_head node;
+ struct device *dev;
+ void __iomem *regs;
+ int duty_ns;
+ int period_ns;
+ char enabled;
+ void (*handler)(struct pwm_device *pwm);
+
+ const char *label;
+ unsigned int use_count;
+ unsigned int pwm_id;
+};
+
+struct sm501pwm_info {
+ void __iomem *regs;
+ int irq;
+ struct resource *res;
+ struct device *dev;
+ struct dentry *debugfs;
+
+ struct pwm_device pwm[3];
+};
+
+int pwm_config(struct pwm_device *pwm, int duty_ns, int period_ns)
+{
+ unsigned int high, low, divider;
+ int divider1, divider2;
+ unsigned long long delay;
+
+ if (!pwm || !pwm->regs || period_ns == 0 || duty_ns > period_ns)
+ return -EINVAL;
+
+ /* Get delay
+ * We're loosing some precision but multiplying then dividing
+ * will overflow
+ */
+ if (period_ns > 1000) {
+ delay = period_ns / 1000;
+ delay *= INPUT_CLOCK;
+ } else {
+ delay = period_ns * 96;
+ delay /= 1000;
+ }
+
+ /* Get the number of clock low and high */
+ high = delay * duty_ns / period_ns;
+ low = delay - high;
+
+ /* Get divider to make 'low' and 'high' fit into 12 bits */
+ /* No need to say that the divider must be >= 0 */
+ divider1 = fls(low)-12;
+ divider2 = fls(high)-12;
+
+ if (divider1 < 0)
+ divider1 = 0;
+ if (divider2 < 0)
+ divider2 = 0;
+
+ divider = max(divider1, divider2);
+
+ low >>= divider;
+ high >>= divider;
+
+ pwm->duty_ns = duty_ns;
+ pwm->period_ns = period_ns;
+
+ writel((high<<20)|(low<<8)|(divider<<4), pwm->regs);
+ return 0;
+}
+EXPORT_SYMBOL(pwm_config);
+
+int pwm_enable(struct pwm_device *pwm)
+{
+ u32 reg;
+
+ if (!pwm)
+ return -EINVAL;
+
+ switch (pwm->pwm_id) {
+ case 0:
+ sm501_configure_gpio(pwm->dev->parent, 29, 1);
+ break;
+ case 1:
+ sm501_configure_gpio(pwm->dev->parent, 30, 1);
+ break;
+ case 2:
+ sm501_configure_gpio(pwm->dev->parent, 31, 1);
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ reg = readl(pwm->regs);
+ reg |= (SM501PWM_IP | SM501PWM_E);
+ writel(reg, pwm->regs);
+ pwm->enabled = 1;
+
+ return 0;
+}
+EXPORT_SYMBOL(pwm_enable);
+
+void pwm_disable(struct pwm_device *pwm)
+{
+ u32 reg;
+
+ if (!pwm)
+ return;
+
+ reg = readl(pwm->regs);
+ reg &= ~(SM501PWM_IP | SM501PWM_E);
+ writel(reg, pwm->regs);
+
+ switch (pwm->pwm_id) {
+ case 0:
+ sm501_configure_gpio(pwm->dev->parent, 29, 0);
+ break;
+ case 1:
+ sm501_configure_gpio(pwm->dev->parent, 30, 0);
+ break;
+ case 2:
+ sm501_configure_gpio(pwm->dev->parent, 31, 0);
+ break;
+ default:
+ break;
+ }
+ pwm->enabled = 0;
+}
+EXPORT_SYMBOL(pwm_disable);
+
+static DEFINE_MUTEX(pwm_lock);
+static LIST_HEAD(pwm_list);
+
+struct pwm_device *pwm_request(int pwm_id, const char *label)
+{
+ struct pwm_device *pwm;
+ int found = 0;
+
+ mutex_lock(&pwm_lock);
+
+ list_for_each_entry(pwm, &pwm_list, node) {
+ if (pwm->pwm_id == pwm_id && pwm->use_count == 0) {
+ pwm->use_count++;
+ pwm->label = label;
+ found = 1;
+ break;
+ }
+ }
+
+ mutex_unlock(&pwm_lock);
+
+ return (found) ? pwm : NULL;
+}
+EXPORT_SYMBOL(pwm_request);
+
+void pwm_free(struct pwm_device *pwm)
+{
+ mutex_lock(&pwm_lock);
+
+ if (pwm->use_count) {
+ pwm->use_count--;
+ pwm->label = NULL;
+ } else
+ dev_warn(pwm->dev, "PWM device already freed\n");
+
+ mutex_unlock(&pwm_lock);
+}
+EXPORT_SYMBOL(pwm_free);
+
+int pwm_int_enable(struct pwm_device *pwm)
+{
+ unsigned long conf;
+
+ if (!pwm || !pwm->regs || !pwm->handler)
+ return -EINVAL;
+
+ conf = readl(pwm->regs);
+ conf |= SM501PWM_I;
+ writel(conf, pwm->regs);
+ return 0;
+}
+EXPORT_SYMBOL(pwm_int_enable);
+
+int pwm_int_disable(struct pwm_device *pwm)
+{
+ unsigned long conf;
+
+ if (!pwm || !pwm->regs || !pwm->handler)
+ return -EINVAL;
+
+ conf = readl(pwm->regs);
+ conf &= ~SM501PWM_I;
+ writel(conf, pwm->regs);
+ return 0;
+}
+EXPORT_SYMBOL(pwm_int_disable);
+
+int pwm_set_handler(struct pwm_device *pwm,
+ void (*handler)(struct pwm_device *pwm))
+{
+ if (!pwm || !handler)
+ return -EINVAL;
+ pwm->handler = handler;
+ return 0;
+}
+EXPORT_SYMBOL(pwm_set_handler);
+
+static irqreturn_t sm501pwm_irq(int irq, void *dev_id)
+{
+ unsigned long value;
+ struct sm501pwm_info *info = (struct sm501pwm_info *)dev_id;
+ struct pwm_device *pwm;
+ int i;
+
+ value = sm501_modify_reg(info->dev->parent, SM501_IRQ_STATUS, 0, 0);
+
+ /* Check is the interrupt is for us */
+ if (value & (1<<22)) {
+ for (i = 0 ; i < PWM_COUNT ; i++) {
+ /*
+ * Find which pwm triggered the interrupt
+ * and ack
+ */
+ value = readl(info->regs + i*4);
+ if (value & SM501PWM_IP)
+ writel(value | SM501PWM_IP, info->regs + i*4);
+
+ pwm = &info->pwm[i];
+ if (pwm->handler)
+ pwm->handler(pwm);
+ }
+ return IRQ_HANDLED;
+ }
+
+ return IRQ_NONE;
+}
+
+static void add_pwm(int id, struct sm501pwm_info *info)
+{
+ struct pwm_device *pwm = &info->pwm[id];
+
+ pwm->use_count = 0;
+ pwm->pwm_id = id;
+ pwm->dev = info->dev;
+ pwm->regs = info->regs + id * 4;
+
+ mutex_lock(&pwm_lock);
+ list_add_tail(&pwm->node, &pwm_list);
+ mutex_unlock(&pwm_lock);
+}
+
+static void del_pwm(int id, struct sm501pwm_info *info)
+{
+ struct pwm_device *pwm = &info->pwm[id];
+
+ pwm->use_count = 0;
+ pwm->pwm_id = -1;
+ mutex_lock(&pwm_lock);
+ list_del(&pwm->node);
+ mutex_unlock(&pwm_lock);
+}
+
+/* Debug fs */
+static int sm501pwm_show(struct seq_file *s, void *p)
+{
+ struct pwm_device *pwm;
+
+ mutex_lock(&pwm_lock);
+ list_for_each_entry(pwm, &pwm_list, node) {
+ if (pwm->use_count) {
+ seq_printf(s, "pwm-%d (%12s) %d %d %s\n",
+ pwm->pwm_id, pwm->label,
+ pwm->duty_ns, pwm->period_ns,
+ pwm->enabled ? "on" : "off");
+ seq_printf(s, " %08x\n", readl(pwm->regs));
+ }
+ }
+ mutex_unlock(&pwm_lock);
+
+ return 0;
+}
+
+static int sm501pwm_open(struct inode *inode, struct file *file)
+{
+ return single_open(file, sm501pwm_show, inode->i_private);
+}
+
+static const struct file_operations sm501pwm_fops = {
+ .open = sm501pwm_open,
+ .read = seq_read,
+ .llseek = seq_lseek,
+ .release = single_release,
+ .owner = THIS_MODULE,
+};
+
+static int __init sm501pwm_probe(struct platform_device *pdev)
+{
+ struct sm501pwm_info *info;
+ struct device *dev = &pdev->dev;
+ struct resource *res;
+ int ret = 0;
+ int res_len;
+ int i;
+
+ info = kzalloc(sizeof(struct sm501pwm_info), GFP_KERNEL);
+ if (!info) {
+ dev_err(dev, "Allocation failure\n");
+ ret = -ENOMEM;
+ goto err;
+ }
+ info->dev = dev;
+ platform_set_drvdata(pdev, info);
+
+ /* Get irq number */
+ info->irq = platform_get_irq(pdev, 0);
+ if (!info->irq) {
+ dev_err(dev, "no irq found\n");
+ ret = -ENODEV;
+ goto err_alloc;
+ }
+
+ /* Get regs address */
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (res == NULL) {
+ dev_err(dev, "No memory resource found\n");
+ ret = -ENODEV;
+ goto err_alloc;
+ }
+ info->res = res;
+ res_len = (res->end - res->start)+1;
+
+ if (!request_mem_region(res->start, res_len, drv_name)) {
+ dev_err(dev, "Can't request iomem resource\n");
+ ret = -EBUSY;
+ goto err_alloc;
+ }
+
+ info->regs = ioremap(res->start, res_len);
+ if (!info->regs) {
+ dev_err(dev, "ioremap failed\n");
+ ret = -ENOMEM;
+ goto err_mem;
+ }
+
+ ret = request_irq(info->irq, sm501pwm_irq, IRQF_SHARED, drv_name, info);
+ if (ret != 0) {
+ dev_err(dev, "can't get irq\n");
+ goto err_map;
+ }
+
+
+ sm501_unit_power(info->dev->parent, SM501_GATE_GPIO, 1);
+
+ for (i = 0; i < 3; i++)
+ add_pwm(i, info);
+
+ dev_info(dev, "SM501 PWM Found at %lx irq %d\n",
+ (unsigned long)info->res->start, info->irq);
+
+ info->debugfs = debugfs_create_file("pwm", S_IFREG | S_IRUGO,
+ NULL, info, &sm501pwm_fops);
+
+
+ return 0;
+
+err_map:
+ iounmap(info->regs);
+
+err_mem:
+ release_mem_region(res->start, res_len);
+
+err_alloc:
+ kfree(info);
+ platform_set_drvdata(pdev, NULL);
+err:
+ return ret;
+}
+
+static int sm501pwm_remove(struct platform_device *pdev)
+{
+ struct sm501pwm_info *info = platform_get_drvdata(pdev);
+ int i;
+
+ if (info->debugfs)
+ debugfs_remove(info->debugfs);
+
+ for (i = 0; i < 3; i++) {
+ pwm_disable(&info->pwm[i]);
+ del_pwm(i, info);
+ }
+
+ sm501_unit_power(info->dev->parent, SM501_GATE_GPIO, 0);
+ sm501_modify_reg(info->dev->parent, SM501_IRQ_STATUS, 0, 1<<22);
+
+ free_irq(info->irq, info);
+ iounmap(info->regs);
+ release_mem_region(info->res->start,
+ (info->res->end - info->res->start)+1);
+ kfree(info);
+ platform_set_drvdata(pdev, NULL);
+
+ return 0;
+}
+
+static struct platform_driver sm501pwm_driver = {
+ .probe = sm501pwm_probe,
+ .remove = sm501pwm_remove,
+ .driver = {
+ .name = drv_name,
+ .owner = THIS_MODULE,
+ },
+};
+
+static int __devinit sm501pwm_init(void)
+{
+ return platform_driver_register(&sm501pwm_driver);
+}
+
+static void __exit sm501pwm_cleanup(void)
+{
+ platform_driver_unregister(&sm501pwm_driver);
+}
+
+module_init(sm501pwm_init);
+module_exit(sm501pwm_cleanup);
+
+MODULE_AUTHOR("Arnaud Patard <apatard@mandriva.com>");
+MODULE_DESCRIPTION("SM501 PWM driver");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:sm501-pwm");
diff --git a/arch/mips/loongson/lemote-2f/Makefile b/arch/mips/loongson/lemote-2f/Makefile
index 8699a53..10e9eb7 100644
--- a/arch/mips/loongson/lemote-2f/Makefile
+++ b/arch/mips/loongson/lemote-2f/Makefile
@@ -2,7 +2,7 @@
# Makefile for lemote loongson2f family machines
#
-obj-y += machtype.o irq.o reset.o ec_kb3310b.o
+obj-y += machtype.o irq.o reset.o ec_kb3310b.o platform.o
#
# Suspend Support
diff --git a/arch/mips/loongson/lemote-2f/ec_kb3310b.c b/arch/mips/loongson/lemote-2f/ec_kb3310b.c
index 2b666d3..88ef558 100644
--- a/arch/mips/loongson/lemote-2f/ec_kb3310b.c
+++ b/arch/mips/loongson/lemote-2f/ec_kb3310b.c
@@ -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 @@
spin_unlock_irqrestore(&port_access_lock, flags);
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);
+ }
return ret;
}
@@ -116,8 +113,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 --git a/arch/mips/loongson/lemote-2f/irq.c b/arch/mips/loongson/lemote-2f/irq.c
index 14b0818..d95487c 100644
--- a/arch/mips/loongson/lemote-2f/irq.c
+++ b/arch/mips/loongson/lemote-2f/irq.c
@@ -11,9 +11,7 @@
#include <linux/interrupt.h>
#include <linux/module.h>
-#include <asm/irq_cpu.h>
#include <asm/i8259.h>
-#include <asm/mipsregs.h>
#include <loongson.h>
#include <machine.h>
@@ -107,21 +105,10 @@
void __init mach_init_irq(void)
{
- /* init all controller
- * 0-15 ------> i8259 interrupt
- * 16-23 ------> mips cpu interrupt
- * 32-63 ------> bonito irq
- */
-
/* setup cs5536 as high level trigger */
LOONGSON_INTPOL = LOONGSON_INT_BIT_INT0 | LOONGSON_INT_BIT_INT1;
LOONGSON_INTEDGE &= ~(LOONGSON_INT_BIT_INT0 | LOONGSON_INT_BIT_INT1);
- /* Sets the first-level interrupt dispatcher. */
- mips_cpu_irq_init();
- init_i8259_irqs();
- bonito_irq_init();
-
/* setup north bridge irq (bonito) */
setup_irq(LOONGSON_NORTH_BRIDGE_IRQ, &ip6_irqaction);
/* setup source bridge irq (i8259) */
diff --git a/arch/mips/loongson/lemote-2f/platform.c b/arch/mips/loongson/lemote-2f/platform.c
new file mode 100644
index 0000000..5316360
--- /dev/null
+++ b/arch/mips/loongson/lemote-2f/platform.c
@@ -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 --git a/arch/mips/loongson/lemote-2f/pm.c b/arch/mips/loongson/lemote-2f/pm.c
index cac4d38..b82ab17 100644
--- a/arch/mips/loongson/lemote-2f/pm.c
+++ b/arch/mips/loongson/lemote-2f/pm.c
@@ -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
@@ -88,7 +88,7 @@
static void yeeloong_lid_update_task(struct work_struct *work)
{
if (yeeloong_report_lid_status)
- yeeloong_report_lid_status(BIT_LID_DETECT_ON);
+ yeeloong_report_lid_status(ON);
}
int wakeup_loongson(void)
@@ -100,7 +100,7 @@
if (irq < 0)
return 0;
- printk(KERN_INFO "%s: irq = %d\n", __func__, irq);
+ pr_debug("%s: irq = %d\n", __func__, irq);
if (irq == I8042_KBD_IRQ)
return 1;
@@ -118,7 +118,7 @@
/* check the LID status */
lid_status = ec_read(REG_LID_DETECT);
/* wakeup cpu when people open the LID */
- if (lid_status == BIT_LID_DETECT_ON) {
+ if (lid_status == ON) {
/* If we call it directly here, the WARNING
* will be sent out by getnstimeofday
* via "WARN_ON(timekeeping_suspended);"
@@ -140,10 +140,10 @@
void __weak mach_suspend(void)
{
- disable_mfgpt0_counter();
+ disable_mfgpt_counter();
}
void __weak mach_resume(void)
{
- enable_mfgpt0_counter();
+ enable_mfgpt_counter();
}
diff --git a/arch/mips/loongson/lemote-2f/reset.c b/arch/mips/loongson/lemote-2f/reset.c
index 36020a0..039c2ce 100644
--- a/arch/mips/loongson/lemote-2f/reset.c
+++ b/arch/mips/loongson/lemote-2f/reset.c
@@ -20,15 +20,14 @@
#include <loongson.h>
#include <cs5536/cs5536.h>
-#include "ec_kb3310b.h"
+#include <ec_kb3310b.h>
static void reset_cpu(void)
{
/*
- * reset cpu to full speed, this is needed when enabling cpu frequency
- * scalling
+ * reset cpu to full speed
*/
- LOONGSON_CHIPCFG0 |= 0x7;
+ LOONGSON_CHIPCFG0 |= 7;
}
/* reset support for fuloong2f */
@@ -81,7 +80,7 @@
reset_cpu();
/* sending an reset signal to EC(embedded controller) */
- ec_write(REG_RESET, BIT_RESET_ON);
+ ec_write(REG_RESET, ON);
}
#define yl2f89_reboot ml2f_reboot
diff --git a/arch/mips/math-emu/cp1emu.c b/arch/mips/math-emu/cp1emu.c
index dbf2f93..166b2a4 100644
--- a/arch/mips/math-emu/cp1emu.c
+++ b/arch/mips/math-emu/cp1emu.c
@@ -7,6 +7,9 @@
* Kevin D. Kissell, kevink@mips.com and Carsten Langgaard, carstenl@mips.com
* Copyright (C) 2000 MIPS Technologies, Inc.
*
+ * Loongson instruction support
+ * Copyright (C) 2011 Mark H Weaver <mhw@netris.org>
+ *
* 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
* published by the Free Software Foundation.
@@ -57,6 +60,14 @@
#endif
#define __mips 4
+#ifdef __loongson_fp
+#undef __loongson_fp
+#endif
+#if __mips >= 4 && __mips != 32
+/* Include support for Loongson floating point instructions */
+#define __loongson_fp 1
+#endif
+
/* Function which emulates a floating point instruction. */
static int fpu_emu(struct pt_regs *, struct mips_fpu_struct *,
@@ -66,6 +77,10 @@
static int fpux_emu(struct pt_regs *,
struct mips_fpu_struct *, mips_instruction, void *__user *);
#endif
+#ifdef __loongson_fp
+static int loongson_spec2_emu(struct pt_regs *,
+ struct mips_fpu_struct *, mips_instruction, void *__user *);
+#endif
/* Further private data for which no space exists in mips_fpu_struct */
@@ -203,6 +218,14 @@
#define DPFROMREG(dp, x) DIFROMREG((dp).bits, x)
#define DPTOREG(dp, x) DITOREG((dp).bits, x)
+/* Support for Loongson paired single floating-point format */
+#define PSIFROMREG(si1, si2, x) ({ u64 di; DIFROMREG(di, x); \
+ (si1) = (u32)di; (si2) = (u32)(di >> 32); })
+#define PSITOREG(si1, si2, x) DITOREG((si1) | ((u64)(si2) << 32), x)
+
+#define PSPFROMREG(sp1, sp2, x) PSIFROMREG((sp1).bits, (sp2).bits, x)
+#define PSPTOREG(sp1, sp2, x) PSITOREG((sp1).bits, (sp2).bits, x)
+
/*
* Emulate the single floating point instruction pointed at by EPC.
* Two instructions if the instruction is in a branch delay slot.
@@ -568,6 +591,15 @@
break;
#endif
+#ifdef __loongson_fp
+ case spec2_op:{
+ int sig = loongson_spec2_emu(xcp, ctx, ir, fault_addr);
+ if (sig)
+ return sig;
+ break;
+ }
+#endif
+
default:
return SIGILL;
}
@@ -646,6 +678,172 @@
DEF3OP(nmadd, dp, ieee754dp_mul, ieee754dp_add, ieee754dp_neg);
DEF3OP(nmsub, dp, ieee754dp_mul, ieee754dp_sub, ieee754dp_neg);
+#ifdef __loongson_fp
+static int loongson_spec2_emu(struct pt_regs *xcp, struct mips_fpu_struct *ctx,
+ mips_instruction ir, void *__user *fault_addr)
+{
+ int rfmt; /* resulting format */
+ unsigned rcsr = 0; /* resulting csr */
+ union {
+ ieee754dp d;
+ struct {
+ ieee754sp s;
+ ieee754sp s2;
+ };
+ } rv; /* resulting value */
+
+ /* XXX maybe add a counter for loongson spec2 fp instructions? */
+ /* MIPS_FPU_EMU_INC_STATS(cp1xops); */
+
+ switch (rfmt = (MIPSInst_FFMT(ir) & 0xf)) {
+ case s_fmt:{
+ ieee754sp(*handler) (ieee754sp, ieee754sp, ieee754sp);
+ ieee754sp fd, fs, ft;
+
+ switch (MIPSInst_FUNC(ir)) {
+ case loongson_madd_op:
+ handler = fpemu_sp_madd;
+ goto scoptop;
+ case loongson_msub_op:
+ handler = fpemu_sp_msub;
+ goto scoptop;
+ case loongson_nmadd_op:
+ handler = fpemu_sp_nmadd;
+ goto scoptop;
+ case loongson_nmsub_op:
+ handler = fpemu_sp_nmsub;
+ goto scoptop;
+
+ scoptop:
+ SPFROMREG(fd, MIPSInst_FD(ir));
+ SPFROMREG(fs, MIPSInst_FS(ir));
+ SPFROMREG(ft, MIPSInst_FT(ir));
+ rv.s = (*handler) (fd, fs, ft);
+
+ copcsr:
+ if (ieee754_cxtest(IEEE754_INEXACT))
+ rcsr |= FPU_CSR_INE_X | FPU_CSR_INE_S;
+ if (ieee754_cxtest(IEEE754_UNDERFLOW))
+ rcsr |= FPU_CSR_UDF_X | FPU_CSR_UDF_S;
+ if (ieee754_cxtest(IEEE754_OVERFLOW))
+ rcsr |= FPU_CSR_OVF_X | FPU_CSR_OVF_S;
+ if (ieee754_cxtest(IEEE754_INVALID_OPERATION))
+ rcsr |= FPU_CSR_INV_X | FPU_CSR_INV_S;
+
+ break;
+
+ default:
+ return SIGILL;
+ }
+ break;
+ }
+
+ case d_fmt:{
+ ieee754dp(*handler) (ieee754dp, ieee754dp, ieee754dp);
+ ieee754dp fd, fs, ft;
+
+ switch (MIPSInst_FUNC(ir)) {
+ case loongson_madd_op:
+ handler = fpemu_dp_madd;
+ goto dcoptop;
+ case loongson_msub_op:
+ handler = fpemu_dp_msub;
+ goto dcoptop;
+ case loongson_nmadd_op:
+ handler = fpemu_dp_nmadd;
+ goto dcoptop;
+ case loongson_nmsub_op:
+ handler = fpemu_dp_nmsub;
+ goto dcoptop;
+
+ dcoptop:
+ DPFROMREG(fd, MIPSInst_FD(ir));
+ DPFROMREG(fs, MIPSInst_FS(ir));
+ DPFROMREG(ft, MIPSInst_FT(ir));
+ rv.d = (*handler) (fd, fs, ft);
+ goto copcsr;
+
+ default:
+ return SIGILL;
+ }
+ break;
+ }
+
+ case ps_fmt:{
+ ieee754sp(*handler) (ieee754sp, ieee754sp, ieee754sp);
+ struct _ieee754_csr ieee754_csr_save;
+ ieee754sp fd1, fs1, ft1;
+ ieee754sp fd2, fs2, ft2;
+
+ switch (MIPSInst_FUNC(ir)) {
+ case loongson_madd_op:
+ handler = fpemu_sp_madd;
+ goto pscoptop;
+ case loongson_msub_op:
+ handler = fpemu_sp_msub;
+ goto pscoptop;
+ case loongson_nmadd_op:
+ handler = fpemu_sp_nmadd;
+ goto pscoptop;
+ case loongson_nmsub_op:
+ handler = fpemu_sp_nmsub;
+ goto pscoptop;
+
+ pscoptop:
+ PSPFROMREG(fd1, fd2, MIPSInst_FD(ir));
+ PSPFROMREG(fs1, fs2, MIPSInst_FS(ir));
+ PSPFROMREG(ft1, ft2, MIPSInst_FT(ir));
+ rv.s = (*handler) (fd1, fs1, ft1);
+ ieee754_csr_save = ieee754_csr;
+ rv.s2 = (*handler) (fd2, fs2, ft2);
+ ieee754_csr.cx |= ieee754_csr_save.cx;
+ ieee754_csr.sx |= ieee754_csr_save.sx;
+ goto copcsr;
+
+ default:
+ return SIGILL;
+ }
+ break;
+ }
+
+ default:
+ return SIGILL;
+ }
+
+ /*
+ * Update the fpu CSR register for this operation.
+ * If an exception is required, generate a tidy SIGFPE exception,
+ * without updating the result register.
+ * Note: cause exception bits do not accumulate, they are rewritten
+ * for each op; only the flag/sticky bits accumulate.
+ */
+ ctx->fcr31 = (ctx->fcr31 & ~FPU_CSR_ALL_X) | rcsr;
+ if ((ctx->fcr31 >> 5) & ctx->fcr31 & FPU_CSR_ALL_E) {
+ /*printk ("SIGFPE: fpu csr = %08x\n",ctx->fcr31); */
+ return SIGFPE;
+ }
+
+ /*
+ * Now we can safely write the result back to the register file.
+ */
+ switch (rfmt) {
+ case d_fmt:
+ DPTOREG(rv.d, MIPSInst_FD(ir));
+ break;
+ case s_fmt:
+ SPTOREG(rv.s, MIPSInst_FD(ir));
+ break;
+ case ps_fmt:
+ PSPTOREG(rv.s, rv.s2, MIPSInst_FD(ir));
+ break;
+ default:
+ return SIGILL;
+ }
+
+ return 0;
+}
+#endif
+
static int fpux_emu(struct pt_regs *xcp, struct mips_fpu_struct *ctx,
mips_instruction ir, void *__user *fault_addr)
{
@@ -739,7 +937,7 @@
break;
default:
- return SIGILL;
+ goto SIGILL_unless_prefx_op;
}
break;
}
@@ -809,19 +1007,17 @@
goto copcsr;
default:
- return SIGILL;
+ goto SIGILL_unless_prefx_op;
}
break;
}
- case 0x7: /* 7 */
- if (MIPSInst_FUNC(ir) != pfetch_op) {
- return SIGILL;
- }
- /* ignore prefx operation */
- break;
-
default:
+ SIGILL_unless_prefx_op:
+ if (MIPSInst_FUNC(ir) == prefx_op) {
+ /* ignore prefx operation */
+ break;
+ }
return SIGILL;
}
@@ -842,7 +1038,12 @@
unsigned cond;
union {
ieee754dp d;
- ieee754sp s;
+ struct {
+ ieee754sp s;
+#ifdef __loongson_fp
+ ieee754sp s2; /* for Loongson paired singles */
+#endif
+ };
int w;
#ifdef __mips64
s64 l;
@@ -914,7 +1115,7 @@
case fmov_op:
/* an easy one */
SPFROMREG(rv.s, MIPSInst_FS(ir));
- goto copcsr;
+ break;
/* binary op on handler */
scopbop:
@@ -1101,7 +1302,7 @@
case fmov_op:
/* an easy one */
DPFROMREG(rv.d, MIPSInst_FS(ir));
- goto copcsr;
+ break;
/* binary op on handler */
dcopbop:{
@@ -1212,6 +1413,83 @@
break;
}
+#ifdef __loongson_fp
+ case ps_fmt:{ /* 6 */
+ /* Support for Loongson paired single fp instructions */
+ union {
+ ieee754sp(*b) (ieee754sp, ieee754sp);
+ ieee754sp(*u) (ieee754sp);
+ } handler;
+
+ switch (MIPSInst_FUNC(ir)) {
+ /* binary ops */
+ case fadd_op:
+ handler.b = ieee754sp_add;
+ goto pscopbop;
+ case fsub_op:
+ handler.b = ieee754sp_sub;
+ goto pscopbop;
+ case fmul_op:
+ handler.b = ieee754sp_mul;
+ goto pscopbop;
+
+ /* unary ops */
+ case fabs_op:
+ handler.u = ieee754sp_abs;
+ goto pscopuop;
+ case fneg_op:
+ handler.u = ieee754sp_neg;
+ goto pscopuop;
+ case fmov_op:
+ /* an easy one */
+ PSPFROMREG(rv.s, rv.s2, MIPSInst_FS(ir));
+ break;
+
+ pscopbop: /* paired binary op handler */
+ {
+ struct _ieee754_csr ieee754_csr_save;
+ ieee754sp fs1, ft1;
+ ieee754sp fs2, ft2;
+
+ PSPFROMREG(fs1, fs2, MIPSInst_FS(ir));
+ PSPFROMREG(ft1, ft2, MIPSInst_FT(ir));
+ rv.s = (*handler.b) (fs1, ft1);
+ ieee754_csr_save = ieee754_csr;
+ rv.s2 = (*handler.b) (fs2, ft2);
+ ieee754_csr.cx |= ieee754_csr_save.cx;
+ ieee754_csr.sx |= ieee754_csr_save.sx;
+ goto copcsr;
+ }
+ pscopuop: /* paired unary op handler */
+ {
+ struct _ieee754_csr ieee754_csr_save;
+ ieee754sp fs1;
+ ieee754sp fs2;
+
+ PSPFROMREG(fs1, fs2, MIPSInst_FS(ir));
+ rv.s = (*handler.u) (fs1);
+ ieee754_csr_save = ieee754_csr;
+ rv.s2 = (*handler.u) (fs2);
+ ieee754_csr.cx |= ieee754_csr_save.cx;
+ ieee754_csr.sx |= ieee754_csr_save.sx;
+ goto copcsr;
+ }
+ break;
+
+ default:
+ if (MIPSInst_FUNC(ir) >= fcmp_op) {
+ /* Loongson fp hardware handles all
+ cases of fp compare insns, so we
+ shouldn't have to */
+ printk ("Loongson paired-single fp compare"
+ " unimplemented in cp1emu.c\n");
+ }
+ return SIGILL;
+ }
+ break;
+ }
+#endif
+
case w_fmt:{
ieee754sp fs;
@@ -1301,6 +1579,11 @@
DITOREG(rv.l, MIPSInst_FD(ir));
break;
#endif
+#ifdef __loongson_fp
+ case ps_fmt:
+ PSPTOREG(rv.s, rv.s2, MIPSInst_FD(ir));
+ break;
+#endif
default:
return SIGILL;
}
diff --git a/arch/mips/mm/c-octeon.c b/arch/mips/mm/c-octeon.c
index 16c4d25..8182758 100644
--- a/arch/mips/mm/c-octeon.c
+++ b/arch/mips/mm/c-octeon.c
@@ -182,7 +182,7 @@
struct cpuinfo_mips *c = ¤t_cpu_data;
config1 = read_c0_config1();
- switch (c->cputype) {
+ switch (current_cpu_type()) {
case CPU_CAVIUM_OCTEON:
case CPU_CAVIUM_OCTEON_PLUS:
c->icache.linesz = 2 << ((config1 >> 19) & 7);
diff --git a/arch/mips/mm/c-r4k.c b/arch/mips/mm/c-r4k.c
index b9aabb9..22a94f1 100644
--- a/arch/mips/mm/c-r4k.c
+++ b/arch/mips/mm/c-r4k.c
@@ -766,7 +766,7 @@
unsigned long config1;
unsigned int lsize;
- switch (c->cputype) {
+ switch (current_cpu_type()) {
case CPU_R4600: /* QED style two way caches? */
case CPU_R4700:
case CPU_R5000:
@@ -854,10 +854,10 @@
write_c0_config(config & ~VR41_CONF_P4K);
case CPU_VR4131:
/* Workaround for cache instruction bug of VR4131 */
- if (c->processor_id == 0x0c80U || c->processor_id == 0x0c81U ||
- c->processor_id == 0x0c82U) {
+ if (current_cpu_prid() == 0x0c80U || current_cpu_prid() == 0x0c81U ||
+ current_cpu_prid() == 0x0c82U) {
config |= 0x00400000U;
- if (c->processor_id == 0x0c80U)
+ if (current_cpu_prid() == 0x0c80U)
config |= VR41_CONF_BP;
write_c0_config(config);
} else
@@ -1005,7 +1005,7 @@
* normally they'd suffer from aliases but magic in the hardware deals
* with that for us so we don't need to take care ourselves.
*/
- switch (c->cputype) {
+ switch (current_cpu_type()) {
case CPU_20KC:
case CPU_25KF:
case CPU_SB1:
@@ -1034,7 +1034,7 @@
c->dcache.flags |= MIPS_CACHE_ALIASES;
}
- switch (c->cputype) {
+ switch (current_cpu_type()) {
case CPU_20KC:
/*
* Some older 20Kc chips doesn't have the 'VI' bit in
@@ -1163,7 +1163,7 @@
* processors don't have a S-cache that would be relevant to the
* Linux memory management.
*/
- switch (c->cputype) {
+ switch (current_cpu_type()) {
case CPU_R4000SC:
case CPU_R4000MC:
case CPU_R4400SC:
@@ -1358,7 +1358,7 @@
extern char __weak except_vec2_sb1;
struct cpuinfo_mips *c = ¤t_cpu_data;
- switch (c->cputype) {
+ switch (current_cpu_type()) {
case CPU_SB1:
case CPU_SB1A:
set_uncached_handler(0x100, &except_vec2_sb1, 0x80);
diff --git a/arch/mips/mm/dma-default.c b/arch/mips/mm/dma-default.c
index 4608491..1e20758 100644
--- a/arch/mips/mm/dma-default.c
+++ b/arch/mips/mm/dma-default.c
@@ -310,7 +310,7 @@
return plat_dma_supported(dev, mask);
}
-void dma_cache_sync(struct device *dev, void *vaddr, size_t size,
+void mips_dma_cache_sync(struct device *dev, void *vaddr, size_t size,
enum dma_data_direction direction)
{
BUG_ON(direction == DMA_NONE);
@@ -320,8 +320,6 @@
__dma_sync_virtual(vaddr, size, direction);
}
-EXPORT_SYMBOL(dma_cache_sync);
-
static struct dma_map_ops mips_default_dma_map_ops = {
.alloc_coherent = mips_dma_alloc_coherent,
.free_coherent = mips_dma_free_coherent,
diff --git a/arch/mips/mm/page.c b/arch/mips/mm/page.c
index 36272f7..24cdc98 100644
--- a/arch/mips/mm/page.c
+++ b/arch/mips/mm/page.c
@@ -212,7 +212,7 @@
* hints are broken.
*/
if (current_cpu_type() == CPU_SB1 &&
- (current_cpu_data.processor_id & 0xff) < 0x02) {
+ cpu_prid_rev() < 0x02) {
pref_src_mode = Pref_Load;
pref_dst_mode = Pref_Store;
} else {
diff --git a/arch/mips/mm/sc-mips.c b/arch/mips/mm/sc-mips.c
index 9cca8de..0e633db 100644
--- a/arch/mips/mm/sc-mips.c
+++ b/arch/mips/mm/sc-mips.c
@@ -72,7 +72,7 @@
unsigned int tmp;
/* Check the bypass bit (L2B) */
- switch (c->cputype) {
+ switch (current_cpu_type()) {
case CPU_34K:
case CPU_74K:
case CPU_1004K:
diff --git a/arch/mips/mm/tlbex.c b/arch/mips/mm/tlbex.c
index e06370f..ef36dcf 100644
--- a/arch/mips/mm/tlbex.c
+++ b/arch/mips/mm/tlbex.c
@@ -136,7 +136,7 @@
*/
static int __cpuinit m4kc_tlbp_war(void)
{
- return (current_cpu_data.processor_id & 0xffff00) ==
+ return (current_cpu_prid() & 0xffff00) ==
(PRID_COMP_MIPS | PRID_IMP_4KC);
}
@@ -575,7 +575,7 @@
default:
panic("No TLB refill handler yet (CPU type: %d)",
- current_cpu_data.cputype);
+ current_cpu_type());
break;
}
}
diff --git a/arch/mips/oprofile/op_model_mipsxx.c b/arch/mips/oprofile/op_model_mipsxx.c
index 54759f1..9d12fac 100644
--- a/arch/mips/oprofile/op_model_mipsxx.c
+++ b/arch/mips/oprofile/op_model_mipsxx.c
@@ -349,7 +349,7 @@
break;
case CPU_R10000:
- if ((current_cpu_data.processor_id & 0xff) == 0x20)
+ if (current_cpu_prid() == 0x20)
op_model_mipsxx_ops.cpu_type = "mips/r10000-v2.x";
else
op_model_mipsxx_ops.cpu_type = "mips/r10000";
diff --git a/arch/mips/pci/Makefile b/arch/mips/pci/Makefile
index 4df8799..7361d01 100644
--- a/arch/mips/pci/Makefile
+++ b/arch/mips/pci/Makefile
@@ -29,6 +29,7 @@
obj-$(CONFIG_SOC_PNX8550) += fixup-pnx8550.o ops-pnx8550.o
obj-$(CONFIG_LEMOTE_FULOONG2E) += fixup-fuloong2e.o ops-loongson2.o
obj-$(CONFIG_LEMOTE_MACH2F) += fixup-lemote2f.o ops-loongson2.o
+obj-$(CONFIG_DEXXON_GDIUM) += fixup-gdium.o ops-loongson2.o
obj-$(CONFIG_MIPS_MALTA) += fixup-malta.o
obj-$(CONFIG_PMC_MSP7120_GW) += fixup-pmcmsp.o ops-pmcmsp.o
obj-$(CONFIG_PMC_MSP7120_EVAL) += fixup-pmcmsp.o ops-pmcmsp.o
diff --git a/arch/mips/pci/fixup-gdium.c b/arch/mips/pci/fixup-gdium.c
new file mode 100644
index 0000000..b296220
--- /dev/null
+++ b/arch/mips/pci/fixup-gdium.c
@@ -0,0 +1,90 @@
+/*
+ * Copyright (C) 2010 yajin <yajin@vm-kernel.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/init.h>
+#include <linux/pci.h>
+
+#include <loongson.h>
+/*
+ * http://www.pcidatabase.com
+ * GDIUM has different PCI mapping
+ * slot 13 (0x1814/0x0301) -> RaLink rt2561 Wireless-G PCI
+ * slog 14 (0x126f/0x0501) -> sm501
+ * slot 15 (0x1033/0x0035) -> NEC Dual OHCI controllers
+ * plus Single EHCI controller
+ * slot 16 (0x10ec/0x8139) -> Realtek 8139c
+ * slot 17 (0x1033/0x00e0) -> NEC USB 2.0 Host Controller
+ */
+
+#undef INT_IRQA
+#undef INT_IRQB
+#undef INT_IRQC
+#undef INT_IRQD
+#define INT_IRQA 36
+#define INT_IRQB 37
+#define INT_IRQC 38
+#define INT_IRQD 39
+
+int __init pcibios_map_irq(const struct pci_dev *dev, u8 slot, u8 pin)
+{
+ int irq = 0;
+
+ switch (slot) {
+ case 13:
+ irq = INT_IRQC + ((pin - 1) & 3);
+ break;
+ case 14:
+ irq = INT_IRQA;
+ break;
+ case 15:
+#if CONFIG_GDIUM_VERSION > 2
+ irq = INT_IRQB;
+#else
+ irq = INT_IRQA + ((pin - 1) & 3);
+#endif
+ break;
+ case 16:
+ irq = INT_IRQD;
+ break;
+#if CONFIG_GDIUM_VERSION > 2
+ case 17:
+ irq = INT_IRQC;
+ break;
+#endif
+ default:
+ pr_info(" strange pci slot number %d on gdium.\n", slot);
+ break;
+ }
+ return irq;
+}
+
+/* Do platform specific device initialization at pci_enable_device() time */
+int pcibios_plat_dev_init(struct pci_dev *dev)
+{
+ return 0;
+}
+
+/* Fixups for the USB host controllers */
+static void __init gdium_usb_host_fixup(struct pci_dev *dev)
+{
+ unsigned int val;
+ pci_read_config_dword(dev, 0xe0, &val);
+#if CONFIG_GDIUM_VERSION > 2
+ pci_write_config_dword(dev, 0xe0, (val & ~3) | 0x3);
+#else
+ pci_write_config_dword(dev, 0xe0, (val & ~7) | 0x5);
+ pci_write_config_dword(dev, 0xe4, 1<<5);
+#endif
+}
+DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_NEC, PCI_DEVICE_ID_NEC_USB,
+ gdium_usb_host_fixup);
+#if CONFIG_GDIUM_VERSION > 2
+DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_NEC, PCI_DEVICE_ID_CT_65550,
+ gdium_usb_host_fixup);
+#endif
diff --git a/arch/mips/pci/pci-vr41xx.c b/arch/mips/pci/pci-vr41xx.c
index 444b8d8..e105c49 100644
--- a/arch/mips/pci/pci-vr41xx.c
+++ b/arch/mips/pci/pci-vr41xx.c
@@ -147,7 +147,7 @@
pciu_write(PCICLKSELREG, EQUAL_VTCLOCK);
else if ((vtclock / 2) < pci_clock_max)
pciu_write(PCICLKSELREG, HALF_VTCLOCK);
- else if (current_cpu_data.processor_id >= PRID_VR4131_REV2_1 &&
+ else if (current_cpu_prid() >= PRID_VR4131_REV2_1 &&
(vtclock / 3) < pci_clock_max)
pciu_write(PCICLKSELREG, ONE_THIRD_VTCLOCK);
else if ((vtclock / 4) < pci_clock_max)
diff --git a/arch/mips/vr41xx/common/init.c b/arch/mips/vr41xx/common/init.c
index 2391632..aca5c76 100644
--- a/arch/mips/vr41xx/common/init.c
+++ b/arch/mips/vr41xx/common/init.c
@@ -43,8 +43,8 @@
vr41xx_calculate_clock_frequency();
tclock = vr41xx_get_tclock_frequency();
- if (current_cpu_data.processor_id == PRID_VR4131_REV2_0 ||
- current_cpu_data.processor_id == PRID_VR4131_REV2_1)
+ if (current_cpu_prid() == PRID_VR4131_REV2_0 ||
+ current_cpu_prid() == PRID_VR4131_REV2_1)
mips_hpt_frequency = tclock / 2;
else
mips_hpt_frequency = tclock / 4;
diff --git a/drivers/ata/pata_cs5536.c b/drivers/ata/pata_cs5536.c
index 628c8fa..a6e6c96 100644
--- a/drivers/ata/pata_cs5536.c
+++ b/drivers/ata/pata_cs5536.c
@@ -44,8 +44,6 @@
module_param_named(msr, use_msr, int, 0644);
MODULE_PARM_DESC(msr, "Force using MSR to configure IDE function (Default: 0)");
#else
-#undef rdmsr /* avoid accidental MSR usage on, e.g. x86-64 */
-#undef wrmsr
#define rdmsr(x, y, z) do { } while (0)
#define wrmsr(x, y, z) do { } while (0)
#define use_msr 0
diff --git a/drivers/hid/Kconfig b/drivers/hid/Kconfig
index 7978c55..18c6e44 100644
--- a/drivers/hid/Kconfig
+++ b/drivers/hid/Kconfig
@@ -614,6 +614,13 @@
---help---
Support for Zydacron remote control.
+config HID_GDIUM
+ bool "Gdium Fn keys support" if EMBEDDED
+ depends on USB_HID && DEXXON_GDIUM
+ default !EMBEDDED
+ ---help---
+ Support for Functions keys available on Gdiums.
+
endmenu
endif # HID_SUPPORT
diff --git a/drivers/hid/Makefile b/drivers/hid/Makefile
index 0a0a38e..8085eef 100644
--- a/drivers/hid/Makefile
+++ b/drivers/hid/Makefile
@@ -75,6 +75,7 @@
obj-$(CONFIG_HID_ZYDACRON) += hid-zydacron.o
obj-$(CONFIG_HID_WACOM) += hid-wacom.o
obj-$(CONFIG_HID_WALTOP) += hid-waltop.o
+obj-$(CONFIG_HID_GDIUM) += hid-gdium.o
obj-$(CONFIG_HID_WIIMOTE) += hid-wiimote.o
obj-$(CONFIG_USB_HID) += usbhid/
diff --git a/drivers/hid/hid-gdium.c b/drivers/hid/hid-gdium.c
new file mode 100644
index 0000000..67cc095
--- /dev/null
+++ b/drivers/hid/hid-gdium.c
@@ -0,0 +1,210 @@
+/*
+ * hid-gdium -- Gdium laptop function keys
+ *
+ * Arnaud Patard <apatard@mandriva.com>
+ *
+ * Based on hid-apple.c
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ */
+
+
+#include <linux/device.h>
+#include <linux/hid.h>
+#include <linux/module.h>
+#include <linux/usb.h>
+
+#include "hid-ids.h"
+
+#define GDIUM_FN_ON 1
+
+static int fnmode = GDIUM_FN_ON;
+module_param(fnmode, int, 0644);
+MODULE_PARM_DESC(fnmode, "Mode of fn key on Gdium (0 = disabled, 1 = Enabled)");
+
+struct gdium_data {
+ unsigned int fn_on;
+};
+
+
+struct gdium_key_translation {
+ u16 from;
+ u16 to;
+};
+
+static struct gdium_key_translation gdium_fn_keys[] = {
+ { KEY_F1, KEY_CAMERA },
+ { KEY_F2, KEY_CONNECT },
+ { KEY_F3, KEY_MUTE },
+ { KEY_F4, KEY_VOLUMEUP},
+ { KEY_F5, KEY_VOLUMEDOWN },
+ { KEY_F6, KEY_SWITCHVIDEOMODE },
+ { KEY_F7, KEY_F19 }, /* F7+12. Have to use existant keycodes */
+ { KEY_F8, KEY_BRIGHTNESSUP },
+ { KEY_F9, KEY_BRIGHTNESSDOWN },
+ { KEY_F10, KEY_SLEEP },
+ { KEY_F11, KEY_PROG1 },
+ { KEY_F12, KEY_PROG2 },
+ { KEY_UP, KEY_PAGEUP },
+ { KEY_DOWN, KEY_PAGEDOWN },
+ { KEY_INSERT, KEY_NUMLOCK },
+ { KEY_DELETE, KEY_SCROLLLOCK },
+ { KEY_T, KEY_STOPCD },
+ { KEY_F, KEY_PREVIOUSSONG },
+ { KEY_H, KEY_NEXTSONG },
+ { KEY_G, KEY_PLAYPAUSE },
+ { }
+};
+
+static struct gdium_key_translation *gdium_find_translation(
+ struct gdium_key_translation *table, u16 from)
+{
+ struct gdium_key_translation *trans;
+
+ /* Look for the translation */
+ for (trans = table; trans->from; trans++)
+ if (trans->from == from)
+ return trans;
+ return NULL;
+}
+
+static int hidinput_gdium_event(struct hid_device *hid, struct input_dev *input,
+ struct hid_usage *usage, __s32 value)
+{
+ struct gdium_data *data = hid_get_drvdata(hid);
+ struct gdium_key_translation *trans;
+ int do_translate;
+
+ if (usage->type != EV_KEY)
+ return 0;
+
+ if ((usage->code == KEY_FN)) {
+ data->fn_on = !!value;
+ input_event(input, usage->type, usage->code, value);
+ return 1;
+ }
+
+ if (fnmode) {
+ trans = gdium_find_translation(gdium_fn_keys, usage->code);
+ if (trans) {
+ do_translate = data->fn_on;
+ if (do_translate) {
+ input_event(input, usage->type, trans->to, value);
+ return 1;
+ }
+ }
+ }
+
+ return 0;
+}
+
+static int gdium_input_event(struct hid_device *hdev, struct hid_field *field,
+ struct hid_usage *usage, __s32 value)
+{
+ if (!(hdev->claimed & HID_CLAIMED_INPUT) || !field->hidinput || !usage->type)
+ return 0;
+
+ if (hidinput_gdium_event(hdev, field->hidinput->input, usage, value))
+ return 1;
+
+ return 0;
+}
+
+
+static void gdium_input_setup(struct input_dev *input)
+{
+ struct gdium_key_translation *trans;
+
+ set_bit(KEY_NUMLOCK, input->keybit);
+
+ /* Enable all needed keys */
+ for (trans = gdium_fn_keys; trans->from; trans++)
+ set_bit(trans->to, input->keybit);
+}
+
+static int gdium_input_mapping(struct hid_device *hdev, struct hid_input *hi,
+ struct hid_field *field, struct hid_usage *usage,
+ unsigned long **bit, int *max)
+{
+ if (((usage->hid & HID_USAGE_PAGE) == HID_UP_KEYBOARD)
+ && ((usage->hid & HID_USAGE) == 0x82)) {
+ hid_map_usage_clear(hi, usage, bit, max, EV_KEY, KEY_FN);
+ gdium_input_setup(hi->input);
+ return 1;
+ }
+ return 0;
+}
+
+static int gdium_input_probe(struct hid_device *hdev, const struct hid_device_id *id)
+{
+ struct gdium_data *data;
+ int ret;
+
+ data = kzalloc(sizeof(*data), GFP_KERNEL);
+ if (!data) {
+ dev_err(&hdev->dev, "can't alloc gdium keyboard data\n");
+ return -ENOMEM;
+ }
+
+ hid_set_drvdata(hdev, data);
+
+ ret = hid_parse(hdev);
+ if (ret) {
+ dev_err(&hdev->dev, "parse failed\n");
+ goto err_free;
+ }
+
+ ret = hid_hw_start(hdev, HID_CONNECT_DEFAULT);
+ if (ret) {
+ dev_err(&hdev->dev, "hw start failed\n");
+ goto err_free;
+ }
+
+ return 0;
+err_free:
+ kfree(data);
+ return ret;
+}
+static void gdium_input_remove(struct hid_device *hdev)
+{
+ hid_hw_stop(hdev);
+ kfree(hid_get_drvdata(hdev));
+}
+
+static const struct hid_device_id gdium_input_devices[] = {
+ { HID_USB_DEVICE(USB_VENDOR_ID_GDIUM, USB_DEVICE_ID_GDIUM) },
+ {}
+};
+MODULE_DEVICE_TABLE(hid, gdium_input_devices);
+
+static struct hid_driver gdium_input_driver = {
+ .name = "gdium-fnkeys",
+ .id_table = gdium_input_devices,
+ .probe = gdium_input_probe,
+ .remove = gdium_input_remove,
+ .event = gdium_input_event,
+ .input_mapping = gdium_input_mapping,
+};
+
+static int gdium_input_init(void)
+{
+ int ret;
+
+ ret = hid_register_driver(&gdium_input_driver);
+ if (ret)
+ pr_err("can't register gdium keyboard driver\n");
+
+ return ret;
+}
+static void gdium_input_exit(void)
+{
+ hid_unregister_driver(&gdium_input_driver);
+}
+
+module_init(gdium_input_init);
+module_exit(gdium_input_exit);
+MODULE_LICENSE("GPL");
+
diff --git a/drivers/hid/hid-ids.h b/drivers/hid/hid-ids.h
index 53c4634..167da93 100644
--- a/drivers/hid/hid-ids.h
+++ b/drivers/hid/hid-ids.h
@@ -706,4 +706,6 @@
#define USB_VENDOR_ID_ZYDACRON 0x13EC
#define USB_DEVICE_ID_ZYDACRON_REMOTE_CONTROL 0x0006
+#define USB_VENDOR_ID_GDIUM 0x04B4
+#define USB_DEVICE_ID_GDIUM 0xe001
#endif
diff --git a/drivers/i2c/busses/Kconfig b/drivers/i2c/busses/Kconfig
index 646068e..f5873f3 100644
--- a/drivers/i2c/busses/Kconfig
+++ b/drivers/i2c/busses/Kconfig
@@ -867,7 +867,7 @@
config SCx200_ACB
tristate "Geode ACCESS.bus support"
- depends on X86_32 && PCI
+ depends on PCI
help
Enable the use of the ACCESS.bus controllers on the Geode SCx200 and
SC1100 processors and the CS5535 and CS5536 Geode companion devices.
diff --git a/drivers/ide/ide-iops.c b/drivers/ide/ide-iops.c
index 376f2dc..b576801 100644
--- a/drivers/ide/ide-iops.c
+++ b/drivers/ide/ide-iops.c
@@ -27,6 +27,10 @@
#include <asm/uaccess.h>
#include <asm/io.h>
+#ifdef CONFIG_LEMOTE_MACH2F
+#include <asm/bootinfo.h>
+#endif
+
void SELECT_MASK(ide_drive_t *drive, int mask)
{
const struct ide_port_ops *port_ops = drive->hwif->port_ops;
@@ -300,6 +304,11 @@
{
const char **list, *m = (char *)&drive->id[ATA_ID_PROD];
+#ifdef CONFIG_LEMOTE_MACH2F
+ if (mips_machtype != MACH_LEMOTE_YL2F89)
+ return;
+#endif
+
for (list = nien_quirk_list; *list != NULL; list++)
if (strstr(m, *list) != NULL) {
drive->dev_flags |= IDE_DFLAG_NIEN_QUIRK;
diff --git a/drivers/mfd/sm501.c b/drivers/mfd/sm501.c
index df3702c..7242f3a 100644
--- a/drivers/mfd/sm501.c
+++ b/drivers/mfd/sm501.c
@@ -58,7 +58,7 @@
struct sm501_gpio {
/* no gpio support, empty definition for sm501_devdata. */
};
-#endif
+#endif /* CONFIG_MFD_SM501_GPIO */
struct sm501_devdata {
spinlock_t reg_lock;
@@ -1143,6 +1143,22 @@
{
return sm->gpio.registered;
}
+
+void sm501_configure_gpio(struct device *dev, unsigned int gpio, unsigned
+ char mode)
+{
+ unsigned long set, reg, offset = gpio;
+
+ if (offset >= 32) {
+ reg = SM501_GPIO63_32_CONTROL;
+ offset = gpio - 32;
+ } else
+ reg = SM501_GPIO31_0_CONTROL;
+
+ set = mode ? 1 << offset : 0;
+
+ sm501_modify_reg(dev, reg, set, 0);
+}
#else
static inline int sm501_register_gpio(struct sm501_devdata *sm)
{
@@ -1162,7 +1178,13 @@
{
return 0;
}
-#endif
+
+void sm501_configure_gpio(struct device *dev, unsigned int gpio,
+ unsigned char mode)
+{
+}
+#endif /* CONFIG_MFD_SM501_GPIO */
+EXPORT_SYMBOL_GPL(sm501_configure_gpio);
static int sm501_register_gpio_i2c_instance(struct sm501_devdata *sm,
struct sm501_platdata_gpio_i2c *iic)
@@ -1217,6 +1239,20 @@
return 0;
}
+/* register sm501 PWM device */
+static int sm501_register_pwm(struct sm501_devdata *sm)
+{
+ struct platform_device *pdev;
+
+ pdev = sm501_create_subdev(sm, "sm501-pwm", 2, 0);
+ if (!pdev)
+ return -ENOMEM;
+ sm501_create_subio(sm, &pdev->resource[0], 0x10020, 0xC);
+ sm501_create_irq(sm, &pdev->resource[1]);
+
+ return sm501_register_device(sm, pdev);
+}
+
/* sm501_dbg_regs
*
* Debug attribute to attach to parent device to show core registers
@@ -1375,6 +1411,8 @@
sm501_register_uart(sm, idata->devices);
if (idata->devices & SM501_USE_GPIO)
sm501_register_gpio(sm);
+ if (idata->devices & SM501_USE_PWM)
+ sm501_register_pwm(sm);
}
if (pdata && pdata->gpio_i2c != NULL && pdata->gpio_i2c_nr > 0) {
@@ -1561,10 +1599,15 @@
.devices = SM501_USE_ALL,
/* Errata AB-3 says that 72MHz is the fastest available
- * for 33MHZ PCI with proper bus-mastering operation */
-
+ * for 33MHZ PCI with proper bus-mastering operation
+ * For gdium, it works under 84&112M clock freq.*/
+#ifdef CONFIG_DEXXON_GDIUM
+ .mclk = 84 * MHZ,
+ .m1xclk = 112 * MHZ,
+#else
.mclk = 72 * MHZ,
.m1xclk = 144 * MHZ,
+#endif
};
static struct sm501_platdata_fbsub sm501_pdata_fbsub = {
diff --git a/drivers/net/Kconfig b/drivers/net/Kconfig
index a44874e..874c90f 100644
--- a/drivers/net/Kconfig
+++ b/drivers/net/Kconfig
@@ -2458,6 +2458,13 @@
Some boards that use the Discovery chipset are the Momenco
Ocelot C and Jaguar ATX and Pegasos II.
+config TITAN_GE
+ bool "PMC-Sierra TITAN Gigabit Ethernet Support"
+ depends on PMC_YOSEMITE
+ help
+ This enables support for the the integrated ethernet of
+ PMC-Sierra's Titan SoC.
+
config XILINX_LL_TEMAC
tristate "Xilinx LL TEMAC (LocalLink Tri-mode Ethernet MAC) driver"
depends on PPC || MICROBLAZE
diff --git a/drivers/net/Makefile b/drivers/net/Makefile
index e1eca2a..e2b0b56 100644
--- a/drivers/net/Makefile
+++ b/drivers/net/Makefile
@@ -158,6 +158,8 @@
obj-$(CONFIG_QLCNIC) += qlcnic/
obj-$(CONFIG_QLGE) += qlge/
+obj-$(CONFIG_TITAN_GE) += titan_mdio.o titan_ge.o
+
obj-$(CONFIG_PPP) += ppp_generic.o
obj-$(CONFIG_PPP_ASYNC) += ppp_async.o
obj-$(CONFIG_PPP_SYNC_TTY) += ppp_synctty.o
diff --git a/drivers/net/titan_ge.c b/drivers/net/titan_ge.c
new file mode 100644
index 0000000..dc137bf8
--- /dev/null
+++ b/drivers/net/titan_ge.c
@@ -0,0 +1,2069 @@
+/*
+ * drivers/net/titan_ge.c - Driver for Titan ethernet ports
+ *
+ * Copyright (C) 2003 PMC-Sierra Inc.
+ * Author : Manish Lachwani (lachwani@pmc-sierra.com)
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+/*
+ * The MAC unit of the Titan consists of the following:
+ *
+ * -> XDMA Engine to move data to from the memory to the MAC packet FIFO
+ * -> FIFO is where the incoming and outgoing data is placed
+ * -> TRTG is the unit that pulls the data from the FIFO for Tx and pushes
+ * the data into the FIFO for Rx
+ * -> TMAC is the outgoing MAC interface and RMAC is the incoming.
+ * -> AFX is the address filtering block
+ * -> GMII block to communicate with the PHY
+ *
+ * Rx will look like the following:
+ * GMII --> RMAC --> AFX --> TRTG --> Rx FIFO --> XDMA --> CPU memory
+ *
+ * Tx will look like the following:
+ * CPU memory --> XDMA --> Tx FIFO --> TRTG --> TMAC --> GMII
+ *
+ * The Titan driver has support for the following performance features:
+ * -> Rx side checksumming
+ * -> Jumbo Frames
+ * -> Interrupt Coalscing
+ * -> Rx NAPI
+ * -> SKB Recycling
+ * -> Transmit/Receive descriptors in SRAM
+ * -> Fast routing for IP forwarding
+ */
+
+#include <linux/dma-mapping.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/ioport.h>
+#include <linux/interrupt.h>
+#include <linux/slab.h>
+#include <linux/string.h>
+#include <linux/errno.h>
+#include <linux/ip.h>
+#include <linux/init.h>
+#include <linux/in.h>
+#include <linux/platform_device.h>
+#include <linux/netdevice.h>
+#include <linux/etherdevice.h>
+#include <linux/skbuff.h>
+#include <linux/mii.h>
+#include <linux/delay.h>
+#include <linux/skbuff.h>
+#include <linux/prefetch.h>
+
+/* For MII specifc registers, titan_mdio.h should be included */
+#include <net/ip.h>
+
+#include <asm/bitops.h>
+#include <asm/io.h>
+#include <asm/types.h>
+#include <asm/pgtable.h>
+#include <asm/system.h>
+#include <asm/titan_dep.h>
+
+#include "titan_ge.h"
+#include "titan_mdio.h"
+
+/* Static Function Declarations */
+static int titan_ge_eth_open(struct net_device *);
+static void titan_ge_eth_stop(struct net_device *);
+static struct net_device_stats *titan_ge_get_stats(struct net_device *);
+static int titan_ge_init_rx_desc_ring(titan_ge_port_info *, int, int,
+ unsigned long, unsigned long,
+ unsigned long);
+static int titan_ge_init_tx_desc_ring(titan_ge_port_info *, int,
+ unsigned long, unsigned long);
+
+static int titan_ge_open(struct net_device *);
+static int titan_ge_start_xmit(struct sk_buff *, struct net_device *);
+static int titan_ge_stop(struct net_device *);
+
+static unsigned long titan_ge_tx_coal(unsigned long, int);
+
+static void titan_ge_port_reset(unsigned int);
+static int titan_ge_free_tx_queue(titan_ge_port_info *);
+static int titan_ge_rx_task(struct net_device *, titan_ge_port_info *);
+static int titan_ge_port_start(struct net_device *, titan_ge_port_info *);
+
+static int titan_ge_return_tx_desc(titan_ge_port_info *, int);
+
+/*
+ * Some configuration for the FIFO and the XDMA channel needs
+ * to be done only once for all the ports. This flag controls
+ * that
+ */
+static unsigned long config_done;
+
+/*
+ * One time out of memory flag
+ */
+static unsigned int oom_flag;
+
+static int titan_ge_poll(struct net_device *netdev, int *budget);
+
+static int titan_ge_receive_queue(struct net_device *, unsigned int);
+
+static struct platform_device *titan_ge_device[3];
+
+/* MAC Address */
+extern unsigned char titan_ge_mac_addr_base[6];
+
+unsigned long titan_ge_base;
+static unsigned long titan_ge_sram;
+
+static char titan_string[] = "titan";
+
+/*
+ * The Titan GE has two alignment requirements:
+ * -> skb->data to be cacheline aligned (32 byte)
+ * -> IP header alignment to 16 bytes
+ *
+ * The latter is not implemented. So, that results in an extra copy on
+ * the Rx. This is a big performance hog. For the former case, the
+ * dev_alloc_skb() has been replaced with titan_ge_alloc_skb(). The size
+ * requested is calculated:
+ *
+ * Ethernet Frame Size : 1518
+ * Ethernet Header : 14
+ * Future Titan change for IP header alignment : 2
+ *
+ * Hence, we allocate (1518 + 14 + 2+ 64) = 1580 bytes. For IP header
+ * alignment, we use skb_reserve().
+ */
+
+#define ALIGNED_RX_SKB_ADDR(addr) \
+ ((((unsigned long)(addr) + (64UL - 1UL)) \
+ & ~(64UL - 1UL)) - (unsigned long)(addr))
+
+#define titan_ge_alloc_skb(__length, __gfp_flags) \
+({ struct sk_buff *__skb; \
+ __skb = alloc_skb((__length) + 64, (__gfp_flags)); \
+ if(__skb) { \
+ int __offset = (int) ALIGNED_RX_SKB_ADDR(__skb->data); \
+ if(__offset) \
+ skb_reserve(__skb, __offset); \
+ } \
+ __skb; \
+})
+
+/*
+ * Configure the GMII block of the Titan based on what the PHY tells us
+ */
+static void titan_ge_gmii_config(int port_num)
+{
+ unsigned int reg_data = 0, phy_reg;
+ int err;
+
+ err = titan_ge_mdio_read(port_num, TITAN_GE_MDIO_PHY_STATUS, &phy_reg);
+
+ if (err == TITAN_GE_MDIO_ERROR) {
+ printk(KERN_ERR
+ "Could not read PHY control register 0x11 \n");
+ printk(KERN_ERR
+ "Setting speed to 1000 Mbps and Duplex to Full \n");
+
+ return;
+ }
+
+ err = titan_ge_mdio_write(port_num, TITAN_GE_MDIO_PHY_IE, 0);
+
+ if (phy_reg & 0x8000) {
+ if (phy_reg & 0x2000) {
+ /* Full Duplex and 1000 Mbps */
+ TITAN_GE_WRITE((TITAN_GE_GMII_CONFIG_MODE +
+ (port_num << 12)), 0x201);
+ } else {
+ /* Half Duplex and 1000 Mbps */
+ TITAN_GE_WRITE((TITAN_GE_GMII_CONFIG_MODE +
+ (port_num << 12)), 0x2201);
+ }
+ }
+ if (phy_reg & 0x4000) {
+ if (phy_reg & 0x2000) {
+ /* Full Duplex and 100 Mbps */
+ TITAN_GE_WRITE((TITAN_GE_GMII_CONFIG_MODE +
+ (port_num << 12)), 0x100);
+ } else {
+ /* Half Duplex and 100 Mbps */
+ TITAN_GE_WRITE((TITAN_GE_GMII_CONFIG_MODE +
+ (port_num << 12)), 0x2100);
+ }
+ }
+ reg_data = TITAN_GE_READ(TITAN_GE_GMII_CONFIG_GENERAL +
+ (port_num << 12));
+ reg_data |= 0x3;
+ TITAN_GE_WRITE((TITAN_GE_GMII_CONFIG_GENERAL +
+ (port_num << 12)), reg_data);
+}
+
+/*
+ * Enable the TMAC if it is not
+ */
+static void titan_ge_enable_tx(unsigned int port_num)
+{
+ unsigned long reg_data;
+
+ reg_data = TITAN_GE_READ(TITAN_GE_TMAC_CONFIG_1 + (port_num << 12));
+ if (!(reg_data & 0x8000)) {
+ printk("TMAC disabled for port %d!! \n", port_num);
+
+ reg_data |= 0x0001; /* Enable TMAC */
+ reg_data |= 0x4000; /* CRC Check Enable */
+ reg_data |= 0x2000; /* Padding enable */
+ reg_data |= 0x0800; /* CRC Add enable */
+ reg_data |= 0x0080; /* PAUSE frame */
+
+ TITAN_GE_WRITE((TITAN_GE_TMAC_CONFIG_1 +
+ (port_num << 12)), reg_data);
+ }
+}
+
+/*
+ * Tx Timeout function
+ */
+static void titan_ge_tx_timeout(struct net_device *netdev)
+{
+ titan_ge_port_info *titan_ge_eth = netdev_priv(netdev);
+
+ printk(KERN_INFO "%s: TX timeout ", netdev->name);
+ printk(KERN_INFO "Resetting card \n");
+
+ /* Do the reset outside of interrupt context */
+ schedule_work(&titan_ge_eth->tx_timeout_task);
+}
+
+/*
+ * Update the AFX tables for UC and MC for slice 0 only
+ */
+static void titan_ge_update_afx(titan_ge_port_info * titan_ge_eth)
+{
+ int port = titan_ge_eth->port_num;
+ unsigned int i;
+ volatile unsigned long reg_data = 0;
+ u8 p_addr[6];
+
+ memcpy(p_addr, titan_ge_eth->port_mac_addr, 6);
+
+ /* Set the MAC address here for TMAC and RMAC */
+ TITAN_GE_WRITE((TITAN_GE_TMAC_STATION_HI + (port << 12)),
+ ((p_addr[5] << 8) | p_addr[4]));
+ TITAN_GE_WRITE((TITAN_GE_TMAC_STATION_MID + (port << 12)),
+ ((p_addr[3] << 8) | p_addr[2]));
+ TITAN_GE_WRITE((TITAN_GE_TMAC_STATION_LOW + (port << 12)),
+ ((p_addr[1] << 8) | p_addr[0]));
+
+ TITAN_GE_WRITE((TITAN_GE_RMAC_STATION_HI + (port << 12)),
+ ((p_addr[5] << 8) | p_addr[4]));
+ TITAN_GE_WRITE((TITAN_GE_RMAC_STATION_MID + (port << 12)),
+ ((p_addr[3] << 8) | p_addr[2]));
+ TITAN_GE_WRITE((TITAN_GE_RMAC_STATION_LOW + (port << 12)),
+ ((p_addr[1] << 8) | p_addr[0]));
+
+ TITAN_GE_WRITE((0x112c | (port << 12)), 0x1);
+ /* Configure the eight address filters */
+ for (i = 0; i < 8; i++) {
+ /* Select each of the eight filters */
+ TITAN_GE_WRITE((TITAN_GE_AFX_ADDRS_FILTER_CTRL_2 +
+ (port << 12)), i);
+
+ /* Configure the match */
+ reg_data = 0x9; /* Forward Enable Bit */
+ TITAN_GE_WRITE((TITAN_GE_AFX_ADDRS_FILTER_CTRL_0 +
+ (port << 12)), reg_data);
+
+ /* Finally, AFX Exact Match Address Registers */
+ TITAN_GE_WRITE((TITAN_GE_AFX_EXACT_MATCH_LOW + (port << 12)),
+ ((p_addr[1] << 8) | p_addr[0]));
+ TITAN_GE_WRITE((TITAN_GE_AFX_EXACT_MATCH_MID + (port << 12)),
+ ((p_addr[3] << 8) | p_addr[2]));
+ TITAN_GE_WRITE((TITAN_GE_AFX_EXACT_MATCH_HIGH + (port << 12)),
+ ((p_addr[5] << 8) | p_addr[4]));
+
+ /* VLAN id set to 0 */
+ TITAN_GE_WRITE((TITAN_GE_AFX_EXACT_MATCH_VID +
+ (port << 12)), 0);
+ }
+}
+
+/*
+ * Actual Routine to reset the adapter when the timeout occurred
+ */
+static void titan_ge_tx_timeout_task(struct net_device *netdev)
+{
+ titan_ge_port_info *titan_ge_eth = netdev_priv(netdev);
+ int port = titan_ge_eth->port_num;
+
+ printk("Titan GE: Transmit timed out. Resetting ... \n");
+
+ /* Dump debug info */
+ printk(KERN_ERR "TRTG cause : %x \n",
+ TITAN_GE_READ(0x100c + (port << 12)));
+
+ /* Fix this for the other ports */
+ printk(KERN_ERR "FIFO cause : %x \n", TITAN_GE_READ(0x482c));
+ printk(KERN_ERR "IE cause : %x \n", TITAN_GE_READ(0x0040));
+ printk(KERN_ERR "XDMA GDI ERROR : %x \n",
+ TITAN_GE_READ(0x5008 + (port << 8)));
+ printk(KERN_ERR "CHANNEL ERROR: %x \n",
+ TITAN_GE_READ(TITAN_GE_CHANNEL0_INTERRUPT
+ + (port << 8)));
+
+ netif_device_detach(netdev);
+ titan_ge_port_reset(titan_ge_eth->port_num);
+ titan_ge_port_start(netdev, titan_ge_eth);
+ netif_device_attach(netdev);
+}
+
+/*
+ * Change the MTU of the Ethernet Device
+ */
+static int titan_ge_change_mtu(struct net_device *netdev, int new_mtu)
+{
+ titan_ge_port_info *titan_ge_eth = netdev_priv(netdev);
+ unsigned long flags;
+
+ if ((new_mtu > 9500) || (new_mtu < 64))
+ return -EINVAL;
+
+ spin_lock_irqsave(&titan_ge_eth->lock, flags);
+
+ netdev->mtu = new_mtu;
+
+ /* Now we have to reopen the interface so that SKBs with the new
+ * size will be allocated */
+
+ if (netif_running(netdev)) {
+ titan_ge_eth_stop(netdev);
+
+ if (titan_ge_eth_open(netdev) != TITAN_OK) {
+ printk(KERN_ERR
+ "%s: Fatal error on opening device\n",
+ netdev->name);
+ spin_unlock_irqrestore(&titan_ge_eth->lock, flags);
+ return -1;
+ }
+ }
+
+ spin_unlock_irqrestore(&titan_ge_eth->lock, flags);
+ return 0;
+}
+
+/*
+ * Titan Gbe Interrupt Handler. All the three ports send interrupt to one line
+ * only. Once an interrupt is triggered, figure out the port and then check
+ * the channel.
+ */
+static irqreturn_t titan_ge_int_handler(int irq, void *dev_id)
+{
+ struct net_device *netdev = (struct net_device *) dev_id;
+ titan_ge_port_info *titan_ge_eth = netdev_priv(netdev);
+ unsigned int port_num = titan_ge_eth->port_num;
+ unsigned int reg_data;
+ unsigned int eth_int_cause_error = 0, is;
+ unsigned long eth_int_cause1;
+ int err = 0;
+#ifdef CONFIG_SMP
+ unsigned long eth_int_cause2;
+#endif
+
+ /* Ack the CPU interrupt */
+ switch (port_num) {
+ case 0:
+ is = OCD_READ(RM9000x2_OCD_INTP0STATUS1);
+ OCD_WRITE(RM9000x2_OCD_INTP0CLEAR1, is);
+
+#ifdef CONFIG_SMP
+ is = OCD_READ(RM9000x2_OCD_INTP1STATUS1);
+ OCD_WRITE(RM9000x2_OCD_INTP1CLEAR1, is);
+#endif
+ break;
+
+ case 1:
+ is = OCD_READ(RM9000x2_OCD_INTP0STATUS0);
+ OCD_WRITE(RM9000x2_OCD_INTP0CLEAR0, is);
+
+#ifdef CONFIG_SMP
+ is = OCD_READ(RM9000x2_OCD_INTP1STATUS0);
+ OCD_WRITE(RM9000x2_OCD_INTP1CLEAR0, is);
+#endif
+ break;
+
+ case 2:
+ is = OCD_READ(RM9000x2_OCD_INTP0STATUS4);
+ OCD_WRITE(RM9000x2_OCD_INTP0CLEAR4, is);
+
+#ifdef CONFIG_SMP
+ is = OCD_READ(RM9000x2_OCD_INTP1STATUS4);
+ OCD_WRITE(RM9000x2_OCD_INTP1CLEAR4, is);
+#endif
+ }
+
+ eth_int_cause1 = TITAN_GE_READ(TITAN_GE_INTR_XDMA_CORE_A);
+#ifdef CONFIG_SMP
+ eth_int_cause2 = TITAN_GE_READ(TITAN_GE_INTR_XDMA_CORE_B);
+#endif
+
+ /* Spurious interrupt */
+#ifdef CONFIG_SMP
+ if ( (eth_int_cause1 == 0) && (eth_int_cause2 == 0)) {
+#else
+ if (eth_int_cause1 == 0) {
+#endif
+ eth_int_cause_error = TITAN_GE_READ(TITAN_GE_CHANNEL0_INTERRUPT +
+ (port_num << 8));
+
+ if (eth_int_cause_error == 0)
+ return IRQ_NONE;
+ }
+
+ /* Handle Tx first. No need to ack interrupts */
+#ifdef CONFIG_SMP
+ if ( (eth_int_cause1 & 0x20202) ||
+ (eth_int_cause2 & 0x20202) )
+#else
+ if (eth_int_cause1 & 0x20202)
+#endif
+ titan_ge_free_tx_queue(titan_ge_eth);
+
+ /* Handle the Rx next */
+#ifdef CONFIG_SMP
+ if ( (eth_int_cause1 & 0x10101) ||
+ (eth_int_cause2 & 0x10101)) {
+#else
+ if (eth_int_cause1 & 0x10101) {
+#endif
+ if (netif_rx_schedule_prep(netdev)) {
+ unsigned int ack;
+
+ ack = TITAN_GE_READ(TITAN_GE_INTR_XDMA_IE);
+ /* Disable Tx and Rx both */
+ if (port_num == 0)
+ ack &= ~(0x3);
+ if (port_num == 1)
+ ack &= ~(0x300);
+
+ if (port_num == 2)
+ ack &= ~(0x30000);
+
+ /* Interrupts have been disabled */
+ TITAN_GE_WRITE(TITAN_GE_INTR_XDMA_IE, ack);
+
+ __netif_rx_schedule(netdev);
+ }
+ }
+
+ /* Handle error interrupts */
+ if (eth_int_cause_error && (eth_int_cause_error != 0x2)) {
+ printk(KERN_ERR
+ "XDMA Channel Error : %x on port %d\n",
+ eth_int_cause_error, port_num);
+
+ printk(KERN_ERR
+ "XDMA GDI Hardware error : %x on port %d\n",
+ TITAN_GE_READ(0x5008 + (port_num << 8)), port_num);
+
+ printk(KERN_ERR
+ "XDMA currently has %d Rx descriptors \n",
+ TITAN_GE_READ(0x5048 + (port_num << 8)));
+
+ printk(KERN_ERR
+ "XDMA currently has prefetcted %d Rx descriptors \n",
+ TITAN_GE_READ(0x505c + (port_num << 8)));
+
+ TITAN_GE_WRITE((TITAN_GE_CHANNEL0_INTERRUPT +
+ (port_num << 8)), eth_int_cause_error);
+ }
+
+ /*
+ * PHY interrupt to inform abt the changes. Reading the
+ * PHY Status register will clear the interrupt
+ */
+ if ((!(eth_int_cause1 & 0x30303)) &&
+ (eth_int_cause_error == 0)) {
+ err =
+ titan_ge_mdio_read(port_num,
+ TITAN_GE_MDIO_PHY_IS, ®_data);
+
+ if (reg_data & 0x0400) {
+ /* Link status change */
+ titan_ge_mdio_read(port_num,
+ TITAN_GE_MDIO_PHY_STATUS, ®_data);
+ if (!(reg_data & 0x0400)) {
+ /* Link is down */
+ netif_carrier_off(netdev);
+ netif_stop_queue(netdev);
+ } else {
+ /* Link is up */
+ netif_carrier_on(netdev);
+ netif_wake_queue(netdev);
+
+ /* Enable the queue */
+ titan_ge_enable_tx(port_num);
+ }
+ }
+ }
+
+ return IRQ_HANDLED;
+}
+
+/*
+ * Multicast and Promiscuous mode set. The
+ * set_multi entry point is called whenever the
+ * multicast address list or the network interface
+ * flags are updated.
+ */
+static void titan_ge_set_multi(struct net_device *netdev)
+{
+ titan_ge_port_info *titan_ge_eth = netdev_priv(netdev);
+ unsigned int port_num = titan_ge_eth->port_num;
+ unsigned long reg_data;
+
+ reg_data = TITAN_GE_READ(TITAN_GE_AFX_ADDRS_FILTER_CTRL_1 +
+ (port_num << 12));
+
+ if (netdev->flags & IFF_PROMISC) {
+ reg_data |= 0x2;
+ }
+ else if (netdev->flags & IFF_ALLMULTI) {
+ reg_data |= 0x01;
+ reg_data |= 0x400; /* Use the 64-bit Multicast Hash bin */
+ }
+ else {
+ reg_data = 0x2;
+ }
+
+ TITAN_GE_WRITE((TITAN_GE_AFX_ADDRS_FILTER_CTRL_1 +
+ (port_num << 12)), reg_data);
+ if (reg_data & 0x01) {
+ TITAN_GE_WRITE((TITAN_GE_AFX_MULTICAST_HASH_LOW +
+ (port_num << 12)), 0xffff);
+ TITAN_GE_WRITE((TITAN_GE_AFX_MULTICAST_HASH_MIDLOW +
+ (port_num << 12)), 0xffff);
+ TITAN_GE_WRITE((TITAN_GE_AFX_MULTICAST_HASH_MIDHI +
+ (port_num << 12)), 0xffff);
+ TITAN_GE_WRITE((TITAN_GE_AFX_MULTICAST_HASH_HI +
+ (port_num << 12)), 0xffff);
+ }
+}
+
+/*
+ * Open the network device
+ */
+static int titan_ge_open(struct net_device *netdev)
+{
+ titan_ge_port_info *titan_ge_eth = netdev_priv(netdev);
+ unsigned int port_num = titan_ge_eth->port_num;
+ unsigned int irq = TITAN_ETH_PORT_IRQ - port_num;
+ int retval;
+
+ retval = request_irq(irq, titan_ge_int_handler,
+ SA_INTERRUPT | SA_SAMPLE_RANDOM , netdev->name, netdev);
+
+ if (retval != 0) {
+ printk(KERN_ERR "Cannot assign IRQ number to TITAN GE \n");
+ return -1;
+ }
+
+ netdev->irq = irq;
+ printk(KERN_INFO "Assigned IRQ %d to port %d\n", irq, port_num);
+
+ spin_lock_irq(&(titan_ge_eth->lock));
+
+ if (titan_ge_eth_open(netdev) != TITAN_OK) {
+ spin_unlock_irq(&(titan_ge_eth->lock));
+ printk("%s: Error opening interface \n", netdev->name);
+ free_irq(netdev->irq, netdev);
+ return -EBUSY;
+ }
+
+ spin_unlock_irq(&(titan_ge_eth->lock));
+
+ return 0;
+}
+
+/*
+ * Allocate the SKBs for the Rx ring. Also used
+ * for refilling the queue
+ */
+static int titan_ge_rx_task(struct net_device *netdev,
+ titan_ge_port_info *titan_ge_port)
+{
+ struct device *device = &titan_ge_device[titan_ge_port->port_num]->dev;
+ volatile titan_ge_rx_desc *rx_desc;
+ struct sk_buff *skb;
+ int rx_used_desc;
+ int count = 0;
+
+ while (titan_ge_port->rx_ring_skbs < titan_ge_port->rx_ring_size) {
+
+ /* First try to get the skb from the recycler */
+#ifdef TITAN_GE_JUMBO_FRAMES
+ skb = titan_ge_alloc_skb(TITAN_GE_JUMBO_BUFSIZE, GFP_ATOMIC);
+#else
+ skb = titan_ge_alloc_skb(TITAN_GE_STD_BUFSIZE, GFP_ATOMIC);
+#endif
+ if (unlikely(!skb)) {
+ /* OOM, set the flag */
+ printk("OOM \n");
+ oom_flag = 1;
+ break;
+ }
+ count++;
+ skb->dev = netdev;
+
+ titan_ge_port->rx_ring_skbs++;
+
+ rx_used_desc = titan_ge_port->rx_used_desc_q;
+ rx_desc = &(titan_ge_port->rx_desc_area[rx_used_desc]);
+
+#ifdef TITAN_GE_JUMBO_FRAMES
+ rx_desc->buffer_addr = dma_map_single(device, skb->data,
+ TITAN_GE_JUMBO_BUFSIZE - 2, DMA_FROM_DEVICE);
+#else
+ rx_desc->buffer_addr = dma_map_single(device, skb->data,
+ TITAN_GE_STD_BUFSIZE - 2, DMA_FROM_DEVICE);
+#endif
+
+ titan_ge_port->rx_skb[rx_used_desc] = skb;
+ rx_desc->cmd_sts = TITAN_GE_RX_BUFFER_OWNED;
+
+ titan_ge_port->rx_used_desc_q =
+ (rx_used_desc + 1) % TITAN_GE_RX_QUEUE;
+ }
+
+ return count;
+}
+
+/*
+ * Actual init of the Tital GE port. There is one register for
+ * the channel configuration
+ */
+static void titan_port_init(struct net_device *netdev,
+ titan_ge_port_info * titan_ge_eth)
+{
+ unsigned long reg_data;
+
+ titan_ge_port_reset(titan_ge_eth->port_num);
+
+ /* First reset the TMAC */
+ reg_data = TITAN_GE_READ(TITAN_GE_CHANNEL0_CONFIG);
+ reg_data |= 0x80000000;
+ TITAN_GE_WRITE(TITAN_GE_CHANNEL0_CONFIG, reg_data);
+
+ udelay(30);
+
+ reg_data = TITAN_GE_READ(TITAN_GE_CHANNEL0_CONFIG);
+ reg_data &= ~(0xc0000000);
+ TITAN_GE_WRITE(TITAN_GE_CHANNEL0_CONFIG, reg_data);
+
+ /* Now reset the RMAC */
+ reg_data = TITAN_GE_READ(TITAN_GE_CHANNEL0_CONFIG);
+ reg_data |= 0x00080000;
+ TITAN_GE_WRITE(TITAN_GE_CHANNEL0_CONFIG, reg_data);
+
+ udelay(30);
+
+ reg_data = TITAN_GE_READ(TITAN_GE_CHANNEL0_CONFIG);
+ reg_data &= ~(0x000c0000);
+ TITAN_GE_WRITE(TITAN_GE_CHANNEL0_CONFIG, reg_data);
+}
+
+/*
+ * Start the port. All the hardware specific configuration
+ * for the XDMA, Tx FIFO, Rx FIFO, TMAC, RMAC, TRTG and AFX
+ * go here
+ */
+static int titan_ge_port_start(struct net_device *netdev,
+ titan_ge_port_info * titan_port)
+{
+ volatile unsigned long reg_data, reg_data1;
+ int port_num = titan_port->port_num;
+ int count = 0;
+ unsigned long reg_data_1;
+
+ if (config_done == 0) {
+ reg_data = TITAN_GE_READ(0x0004);
+ reg_data |= 0x100;
+ TITAN_GE_WRITE(0x0004, reg_data);
+
+ reg_data &= ~(0x100);
+ TITAN_GE_WRITE(0x0004, reg_data);
+
+ /* Turn on GMII/MII mode and turn off TBI mode */
+ reg_data = TITAN_GE_READ(TITAN_GE_TSB_CTRL_1);
+ reg_data |= 0x00000700;
+ reg_data &= ~(0x00800000); /* Fencing */
+
+ TITAN_GE_WRITE(0x000c, 0x00001100);
+
+ TITAN_GE_WRITE(TITAN_GE_TSB_CTRL_1, reg_data);
+
+ /* Set the CPU Resource Limit register */
+ TITAN_GE_WRITE(0x00f8, 0x8);
+
+ /* Be conservative when using the BIU buffers */
+ TITAN_GE_WRITE(0x0068, 0x4);
+ }
+
+ titan_port->tx_threshold = 0;
+ titan_port->rx_threshold = 0;
+
+ /* We need to write the descriptors for Tx and Rx */
+ TITAN_GE_WRITE((TITAN_GE_CHANNEL0_TX_DESC + (port_num << 8)),
+ (unsigned long) titan_port->tx_dma);
+ TITAN_GE_WRITE((TITAN_GE_CHANNEL0_RX_DESC + (port_num << 8)),
+ (unsigned long) titan_port->rx_dma);
+
+ if (config_done == 0) {
+ /* Step 1: XDMA config */
+ reg_data = TITAN_GE_READ(TITAN_GE_XDMA_CONFIG);
+ reg_data &= ~(0x80000000); /* clear reset */
+ reg_data |= 0x1 << 29; /* sparse tx descriptor spacing */
+ reg_data |= 0x1 << 28; /* sparse rx descriptor spacing */
+ reg_data |= (0x1 << 23) | (0x1 << 24); /* Descriptor Coherency */
+ reg_data |= (0x1 << 21) | (0x1 << 22); /* Data Coherency */
+ TITAN_GE_WRITE(TITAN_GE_XDMA_CONFIG, reg_data);
+ }
+
+ /* IR register for the XDMA */
+ reg_data = TITAN_GE_READ(TITAN_GE_GDI_INTERRUPT_ENABLE + (port_num << 8));
+ reg_data |= 0x80068000; /* No Rx_OOD */
+ TITAN_GE_WRITE((TITAN_GE_GDI_INTERRUPT_ENABLE + (port_num << 8)), reg_data);
+
+ /* Start the Tx and Rx XDMA controller */
+ reg_data = TITAN_GE_READ(TITAN_GE_CHANNEL0_CONFIG + (port_num << 8));
+ reg_data &= 0x4fffffff; /* Clear tx reset */
+ reg_data &= 0xfff4ffff; /* Clear rx reset */
+
+#ifdef TITAN_GE_JUMBO_FRAMES
+ reg_data |= 0xa0 | 0x30030000;
+#else
+ reg_data |= 0x40 | 0x20030000;
+#endif
+
+#ifndef CONFIG_SMP
+ reg_data &= ~(0x10);
+ reg_data |= 0x0f; /* All of the packet */
+#endif
+
+ TITAN_GE_WRITE((TITAN_GE_CHANNEL0_CONFIG + (port_num << 8)), reg_data);
+
+ /* Rx desc count */
+ count = titan_ge_rx_task(netdev, titan_port);
+ TITAN_GE_WRITE((0x5048 + (port_num << 8)), count);
+ count = TITAN_GE_READ(0x5048 + (port_num << 8));
+
+ udelay(30);
+
+ /*
+ * Step 2: Configure the SDQPF, i.e. FIFO
+ */
+ if (config_done == 0) {
+ reg_data = TITAN_GE_READ(TITAN_GE_SDQPF_RXFIFO_CTL);
+ reg_data = 0x1;
+ TITAN_GE_WRITE(TITAN_GE_SDQPF_RXFIFO_CTL, reg_data);
+ reg_data &= ~(0x1);
+ TITAN_GE_WRITE(TITAN_GE_SDQPF_RXFIFO_CTL, reg_data);
+ reg_data = TITAN_GE_READ(TITAN_GE_SDQPF_RXFIFO_CTL);
+ TITAN_GE_WRITE(TITAN_GE_SDQPF_RXFIFO_CTL, reg_data);
+
+ reg_data = TITAN_GE_READ(TITAN_GE_SDQPF_TXFIFO_CTL);
+ reg_data = 0x1;
+ TITAN_GE_WRITE(TITAN_GE_SDQPF_TXFIFO_CTL, reg_data);
+ reg_data &= ~(0x1);
+ TITAN_GE_WRITE(TITAN_GE_SDQPF_TXFIFO_CTL, reg_data);
+ reg_data = TITAN_GE_READ(TITAN_GE_SDQPF_TXFIFO_CTL);
+ TITAN_GE_WRITE(TITAN_GE_SDQPF_TXFIFO_CTL, reg_data);
+ }
+ /*
+ * Enable RX FIFO 0, 4 and 8
+ */
+ if (port_num == 0) {
+ reg_data = TITAN_GE_READ(TITAN_GE_SDQPF_RXFIFO_0);
+
+ reg_data |= 0x100000;
+ reg_data |= (0xff << 10);
+
+ TITAN_GE_WRITE(TITAN_GE_SDQPF_RXFIFO_0, reg_data);
+ /*
+ * BAV2,BAV and DAV settings for the Rx FIFO
+ */
+ reg_data1 = TITAN_GE_READ(0x4844);
+ reg_data1 |= ( (0x10 << 20) | (0x10 << 10) | 0x1);
+ TITAN_GE_WRITE(0x4844, reg_data1);
+
+ reg_data &= ~(0x00100000);
+ reg_data |= 0x200000;
+
+ TITAN_GE_WRITE(TITAN_GE_SDQPF_RXFIFO_0, reg_data);
+
+ reg_data = TITAN_GE_READ(TITAN_GE_SDQPF_TXFIFO_0);
+ reg_data |= 0x100000;
+
+ TITAN_GE_WRITE(TITAN_GE_SDQPF_TXFIFO_0, reg_data);
+
+ reg_data |= (0xff << 10);
+
+ TITAN_GE_WRITE(TITAN_GE_SDQPF_TXFIFO_0, reg_data);
+
+ /*
+ * BAV2, BAV and DAV settings for the Tx FIFO
+ */
+ reg_data1 = TITAN_GE_READ(0x4944);
+ reg_data1 = ( (0x1 << 20) | (0x1 << 10) | 0x10);
+
+ TITAN_GE_WRITE(0x4944, reg_data1);
+
+ reg_data &= ~(0x00100000);
+ reg_data |= 0x200000;
+
+ TITAN_GE_WRITE(TITAN_GE_SDQPF_TXFIFO_0, reg_data);
+
+ }
+
+ if (port_num == 1) {
+ reg_data = TITAN_GE_READ(0x4870);
+
+ reg_data |= 0x100000;
+ reg_data |= (0xff << 10) | (0xff + 1);
+
+ TITAN_GE_WRITE(0x4870, reg_data);
+ /*
+ * BAV2,BAV and DAV settings for the Rx FIFO
+ */
+ reg_data1 = TITAN_GE_READ(0x4874);
+ reg_data1 |= ( (0x10 << 20) | (0x10 << 10) | 0x1);
+ TITAN_GE_WRITE(0x4874, reg_data1);
+
+ reg_data &= ~(0x00100000);
+ reg_data |= 0x200000;
+
+ TITAN_GE_WRITE(0x4870, reg_data);
+
+ reg_data = TITAN_GE_READ(0x494c);
+ reg_data |= 0x100000;
+
+ TITAN_GE_WRITE(0x494c, reg_data);
+ reg_data |= (0xff << 10) | (0xff + 1);
+ TITAN_GE_WRITE(0x494c, reg_data);
+
+ /*
+ * BAV2, BAV and DAV settings for the Tx FIFO
+ */
+ reg_data1 = TITAN_GE_READ(0x4950);
+ reg_data1 = ( (0x1 << 20) | (0x1 << 10) | 0x10);
+
+ TITAN_GE_WRITE(0x4950, reg_data1);
+
+ reg_data &= ~(0x00100000);
+ reg_data |= 0x200000;
+
+ TITAN_GE_WRITE(0x494c, reg_data);
+ }
+
+ /*
+ * Titan 1.2 revision does support port #2
+ */
+ if (port_num == 2) {
+ /*
+ * Put the descriptors in the SRAM
+ */
+ reg_data = TITAN_GE_READ(0x48a0);
+
+ reg_data |= 0x100000;
+ reg_data |= (0xff << 10) | (2*(0xff + 1));
+
+ TITAN_GE_WRITE(0x48a0, reg_data);
+ /*
+ * BAV2,BAV and DAV settings for the Rx FIFO
+ */
+ reg_data1 = TITAN_GE_READ(0x48a4);
+ reg_data1 |= ( (0x10 << 20) | (0x10 << 10) | 0x1);
+ TITAN_GE_WRITE(0x48a4, reg_data1);
+
+ reg_data &= ~(0x00100000);
+ reg_data |= 0x200000;
+
+ TITAN_GE_WRITE(0x48a0, reg_data);
+
+ reg_data = TITAN_GE_READ(0x4958);
+ reg_data |= 0x100000;
+
+ TITAN_GE_WRITE(0x4958, reg_data);
+ reg_data |= (0xff << 10) | (2*(0xff + 1));
+ TITAN_GE_WRITE(0x4958, reg_data);
+
+ /*
+ * BAV2, BAV and DAV settings for the Tx FIFO
+ */
+ reg_data1 = TITAN_GE_READ(0x495c);
+ reg_data1 = ( (0x1 << 20) | (0x1 << 10) | 0x10);
+
+ TITAN_GE_WRITE(0x495c, reg_data1);
+
+ reg_data &= ~(0x00100000);
+ reg_data |= 0x200000;
+
+ TITAN_GE_WRITE(0x4958, reg_data);
+ }
+
+ if (port_num == 2) {
+ reg_data = TITAN_GE_READ(0x48a0);
+
+ reg_data |= 0x100000;
+ reg_data |= (0xff << 10) | (2*(0xff + 1));
+
+ TITAN_GE_WRITE(0x48a0, reg_data);
+ /*
+ * BAV2,BAV and DAV settings for the Rx FIFO
+ */
+ reg_data1 = TITAN_GE_READ(0x48a4);
+ reg_data1 |= ( (0x10 << 20) | (0x10 << 10) | 0x1);
+ TITAN_GE_WRITE(0x48a4, reg_data1);
+
+ reg_data &= ~(0x00100000);
+ reg_data |= 0x200000;
+
+ TITAN_GE_WRITE(0x48a0, reg_data);
+
+ reg_data = TITAN_GE_READ(0x4958);
+ reg_data |= 0x100000;
+
+ TITAN_GE_WRITE(0x4958, reg_data);
+ reg_data |= (0xff << 10) | (2*(0xff + 1));
+ TITAN_GE_WRITE(0x4958, reg_data);
+
+ /*
+ * BAV2, BAV and DAV settings for the Tx FIFO
+ */
+ reg_data1 = TITAN_GE_READ(0x495c);
+ reg_data1 = ( (0x1 << 20) | (0x1 << 10) | 0x10);
+
+ TITAN_GE_WRITE(0x495c, reg_data1);
+
+ reg_data &= ~(0x00100000);
+ reg_data |= 0x200000;
+
+ TITAN_GE_WRITE(0x4958, reg_data);
+ }
+
+ /*
+ * Step 3: TRTG block enable
+ */
+ reg_data = TITAN_GE_READ(TITAN_GE_TRTG_CONFIG + (port_num << 12));
+
+ /*
+ * This is the 1.2 revision of the chip. It has fix for the
+ * IP header alignment. Now, the IP header begins at an
+ * aligned address and this wont need an extra copy in the
+ * driver. This performance drawback existed in the previous
+ * versions of the silicon
+ */
+ reg_data_1 = TITAN_GE_READ(0x103c + (port_num << 12));
+ reg_data_1 |= 0x40000000;
+ TITAN_GE_WRITE((0x103c + (port_num << 12)), reg_data_1);
+
+ reg_data_1 |= 0x04000000;
+ TITAN_GE_WRITE((0x103c + (port_num << 12)), reg_data_1);
+
+ mdelay(5);
+
+ reg_data_1 &= ~(0x04000000);
+ TITAN_GE_WRITE((0x103c + (port_num << 12)), reg_data_1);
+
+ mdelay(5);
+
+ reg_data |= 0x0001;
+ TITAN_GE_WRITE((TITAN_GE_TRTG_CONFIG + (port_num << 12)), reg_data);
+
+ /*
+ * Step 4: Start the Tx activity
+ */
+ TITAN_GE_WRITE((TITAN_GE_TMAC_CONFIG_2 + (port_num << 12)), 0xe197);
+#ifdef TITAN_GE_JUMBO_FRAMES
+ TITAN_GE_WRITE((0x1258 + (port_num << 12)), 0x4000);
+#endif
+ reg_data = TITAN_GE_READ(TITAN_GE_TMAC_CONFIG_1 + (port_num << 12));
+ reg_data |= 0x0001; /* Enable TMAC */
+ reg_data |= 0x6c70; /* PAUSE also set */
+
+ TITAN_GE_WRITE((TITAN_GE_TMAC_CONFIG_1 + (port_num << 12)), reg_data);
+
+ udelay(30);
+
+ /* Destination Address drop bit */
+ reg_data = TITAN_GE_READ(TITAN_GE_RMAC_CONFIG_2 + (port_num << 12));
+ reg_data |= 0x218; /* DA_DROP bit and pause */
+ TITAN_GE_WRITE((TITAN_GE_RMAC_CONFIG_2 + (port_num << 12)), reg_data);
+
+ TITAN_GE_WRITE((0x1218 + (port_num << 12)), 0x3);
+
+#ifdef TITAN_GE_JUMBO_FRAMES
+ TITAN_GE_WRITE((0x1208 + (port_num << 12)), 0x4000);
+#endif
+ /* Start the Rx activity */
+ reg_data = TITAN_GE_READ(TITAN_GE_RMAC_CONFIG_1 + (port_num << 12));
+ reg_data |= 0x0001; /* RMAC Enable */
+ reg_data |= 0x0010; /* CRC Check enable */
+ reg_data |= 0x0040; /* Min Frame check enable */
+ reg_data |= 0x4400; /* Max Frame check enable */
+
+ TITAN_GE_WRITE((TITAN_GE_RMAC_CONFIG_1 + (port_num << 12)), reg_data);
+
+ udelay(30);
+
+ /*
+ * Enable the Interrupts for Tx and Rx
+ */
+ reg_data1 = TITAN_GE_READ(TITAN_GE_INTR_XDMA_IE);
+
+ if (port_num == 0) {
+ reg_data1 |= 0x3;
+#ifdef CONFIG_SMP
+ TITAN_GE_WRITE(0x0038, 0x003);
+#else
+ TITAN_GE_WRITE(0x0038, 0x303);
+#endif
+ }
+
+ if (port_num == 1) {
+ reg_data1 |= 0x300;
+ }
+
+ if (port_num == 2)
+ reg_data1 |= 0x30000;
+
+ TITAN_GE_WRITE(TITAN_GE_INTR_XDMA_IE, reg_data1);
+ TITAN_GE_WRITE(0x003c, 0x300);
+
+ if (config_done == 0) {
+ TITAN_GE_WRITE(0x0024, 0x04000024); /* IRQ vector */
+ TITAN_GE_WRITE(0x0020, 0x000fb000); /* INTMSG base */
+ }
+
+ /* Priority */
+ reg_data = TITAN_GE_READ(0x1038 + (port_num << 12));
+ reg_data &= ~(0x00f00000);
+ TITAN_GE_WRITE((0x1038 + (port_num << 12)), reg_data);
+
+ /* Step 5: GMII config */
+ titan_ge_gmii_config(port_num);
+
+ if (config_done == 0) {
+ TITAN_GE_WRITE(0x1a80, 0);
+ config_done = 1;
+ }
+
+ return TITAN_OK;
+}
+
+/*
+ * Function to queue the packet for the Ethernet device
+ */
+static void titan_ge_tx_queue(titan_ge_port_info * titan_ge_eth,
+ struct sk_buff * skb)
+{
+ struct device *device = &titan_ge_device[titan_ge_eth->port_num]->dev;
+ unsigned int curr_desc = titan_ge_eth->tx_curr_desc_q;
+ volatile titan_ge_tx_desc *tx_curr;
+ int port_num = titan_ge_eth->port_num;
+
+ tx_curr = &(titan_ge_eth->tx_desc_area[curr_desc]);
+ tx_curr->buffer_addr =
+ dma_map_single(device, skb->data, skb_headlen(skb),
+ DMA_TO_DEVICE);
+
+ titan_ge_eth->tx_skb[curr_desc] = (struct sk_buff *) skb;
+ tx_curr->buffer_len = skb_headlen(skb);
+
+ /* Last descriptor enables interrupt and changes ownership */
+ tx_curr->cmd_sts = 0x1 | (1 << 15) | (1 << 5);
+
+ /* Kick the XDMA to start the transfer from memory to the FIFO */
+ TITAN_GE_WRITE((0x5044 + (port_num << 8)), 0x1);
+
+ /* Current descriptor updated */
+ titan_ge_eth->tx_curr_desc_q = (curr_desc + 1) % TITAN_GE_TX_QUEUE;
+
+ /* Prefetch the next descriptor */
+ prefetch((const void *)
+ &titan_ge_eth->tx_desc_area[titan_ge_eth->tx_curr_desc_q]);
+}
+
+/*
+ * Actually does the open of the Ethernet device
+ */
+static int titan_ge_eth_open(struct net_device *netdev)
+{
+ titan_ge_port_info *titan_ge_eth = netdev_priv(netdev);
+ unsigned int port_num = titan_ge_eth->port_num;
+ struct device *device = &titan_ge_device[port_num]->dev;
+ unsigned long reg_data;
+ unsigned int phy_reg;
+ int err = 0;
+
+ /* Stop the Rx activity */
+ reg_data = TITAN_GE_READ(TITAN_GE_RMAC_CONFIG_1 + (port_num << 12));
+ reg_data &= ~(0x00000001);
+ TITAN_GE_WRITE((TITAN_GE_RMAC_CONFIG_1 + (port_num << 12)), reg_data);
+
+ /* Clear the port interrupts */
+ TITAN_GE_WRITE((TITAN_GE_CHANNEL0_INTERRUPT + (port_num << 8)), 0x0);
+
+ if (config_done == 0) {
+ TITAN_GE_WRITE(TITAN_GE_INTR_XDMA_CORE_A, 0);
+ TITAN_GE_WRITE(TITAN_GE_INTR_XDMA_CORE_B, 0);
+ }
+
+ /* Set the MAC Address */
+ memcpy(titan_ge_eth->port_mac_addr, netdev->dev_addr, 6);
+
+ if (config_done == 0)
+ titan_port_init(netdev, titan_ge_eth);
+
+ titan_ge_update_afx(titan_ge_eth);
+
+ /* Allocate the Tx ring now */
+ titan_ge_eth->tx_ring_skbs = 0;
+ titan_ge_eth->tx_ring_size = TITAN_GE_TX_QUEUE;
+
+ /* Allocate space in the SRAM for the descriptors */
+ titan_ge_eth->tx_desc_area = (titan_ge_tx_desc *)
+ (titan_ge_sram + TITAN_TX_RING_BYTES * port_num);
+ titan_ge_eth->tx_dma = TITAN_SRAM_BASE + TITAN_TX_RING_BYTES * port_num;
+
+ if (!titan_ge_eth->tx_desc_area) {
+ printk(KERN_ERR
+ "%s: Cannot allocate Tx Ring (size %d bytes) for port %d\n",
+ netdev->name, TITAN_TX_RING_BYTES, port_num);
+ return -ENOMEM;
+ }
+
+ memset(titan_ge_eth->tx_desc_area, 0, titan_ge_eth->tx_desc_area_size);
+
+ /* Now initialize the Tx descriptor ring */
+ titan_ge_init_tx_desc_ring(titan_ge_eth,
+ titan_ge_eth->tx_ring_size,
+ (unsigned long) titan_ge_eth->tx_desc_area,
+ (unsigned long) titan_ge_eth->tx_dma);
+
+ /* Allocate the Rx ring now */
+ titan_ge_eth->rx_ring_size = TITAN_GE_RX_QUEUE;
+ titan_ge_eth->rx_ring_skbs = 0;
+
+ titan_ge_eth->rx_desc_area =
+ (titan_ge_rx_desc *)(titan_ge_sram + 0x1000 + TITAN_RX_RING_BYTES * port_num);
+
+ titan_ge_eth->rx_dma = TITAN_SRAM_BASE + 0x1000 + TITAN_RX_RING_BYTES * port_num;
+
+ if (!titan_ge_eth->rx_desc_area) {
+ printk(KERN_ERR "%s: Cannot allocate Rx Ring (size %d bytes)\n",
+ netdev->name, TITAN_RX_RING_BYTES);
+
+ printk(KERN_ERR "%s: Freeing previously allocated TX queues...",
+ netdev->name);
+
+ dma_free_coherent(device, titan_ge_eth->tx_desc_area_size,
+ (void *) titan_ge_eth->tx_desc_area,
+ titan_ge_eth->tx_dma);
+
+ return -ENOMEM;
+ }
+
+ memset(titan_ge_eth->rx_desc_area, 0, titan_ge_eth->rx_desc_area_size);
+
+ /* Now initialize the Rx ring */
+#ifdef TITAN_GE_JUMBO_FRAMES
+ if ((titan_ge_init_rx_desc_ring
+ (titan_ge_eth, titan_ge_eth->rx_ring_size, TITAN_GE_JUMBO_BUFSIZE,
+ (unsigned long) titan_ge_eth->rx_desc_area, 0,
+ (unsigned long) titan_ge_eth->rx_dma)) == 0)
+#else
+ if ((titan_ge_init_rx_desc_ring
+ (titan_ge_eth, titan_ge_eth->rx_ring_size, TITAN_GE_STD_BUFSIZE,
+ (unsigned long) titan_ge_eth->rx_desc_area, 0,
+ (unsigned long) titan_ge_eth->rx_dma)) == 0)
+#endif
+ panic("%s: Error initializing RX Ring\n", netdev->name);
+
+ /* Fill the Rx ring with the SKBs */
+ titan_ge_port_start(netdev, titan_ge_eth);
+
+ /*
+ * Check if Interrupt Coalscing needs to be turned on. The
+ * values specified in the register is multiplied by
+ * (8 x 64 nanoseconds) to determine when an interrupt should
+ * be sent to the CPU.
+ */
+
+ if (TITAN_GE_TX_COAL) {
+ titan_ge_eth->tx_int_coal =
+ titan_ge_tx_coal(TITAN_GE_TX_COAL, port_num);
+ }
+
+ err = titan_ge_mdio_read(port_num, TITAN_GE_MDIO_PHY_STATUS, &phy_reg);
+ if (err == TITAN_GE_MDIO_ERROR) {
+ printk(KERN_ERR
+ "Could not read PHY control register 0x11 \n");
+ return TITAN_ERROR;
+ }
+ if (!(phy_reg & 0x0400)) {
+ netif_carrier_off(netdev);
+ netif_stop_queue(netdev);
+ return TITAN_ERROR;
+ } else {
+ netif_carrier_on(netdev);
+ netif_start_queue(netdev);
+ }
+
+ return TITAN_OK;
+}
+
+/*
+ * Queue the packet for Tx. Currently no support for zero copy,
+ * checksum offload and Scatter Gather. The chip does support
+ * Scatter Gather only. But, that wont help here since zero copy
+ * requires support for Tx checksumming also.
+ */
+int titan_ge_start_xmit(struct sk_buff *skb, struct net_device *netdev)
+{
+ titan_ge_port_info *titan_ge_eth = netdev_priv(netdev);
+ unsigned long flags;
+ struct net_device_stats *stats;
+//printk("titan_ge_start_xmit\n");
+
+ stats = &titan_ge_eth->stats;
+ spin_lock_irqsave(&titan_ge_eth->lock, flags);
+
+ if ((TITAN_GE_TX_QUEUE - titan_ge_eth->tx_ring_skbs) <=
+ (skb_shinfo(skb)->nr_frags + 1)) {
+ netif_stop_queue(netdev);
+ spin_unlock_irqrestore(&titan_ge_eth->lock, flags);
+ printk(KERN_ERR "Tx OOD \n");
+ return 1;
+ }
+
+ titan_ge_tx_queue(titan_ge_eth, skb);
+ titan_ge_eth->tx_ring_skbs++;
+
+ if (TITAN_GE_TX_QUEUE <= (titan_ge_eth->tx_ring_skbs + 4)) {
+ spin_unlock_irqrestore(&titan_ge_eth->lock, flags);
+ titan_ge_free_tx_queue(titan_ge_eth);
+ spin_lock_irqsave(&titan_ge_eth->lock, flags);
+ }
+
+ stats->tx_bytes += skb->len;
+ stats->tx_packets++;
+
+ spin_unlock_irqrestore(&titan_ge_eth->lock, flags);
+
+ netdev->trans_start = jiffies;
+
+ return 0;
+}
+
+/*
+ * Actually does the Rx. Rx side checksumming supported.
+ */
+static int titan_ge_rx(struct net_device *netdev, int port_num,
+ titan_ge_port_info * titan_ge_port,
+ titan_ge_packet * packet)
+{
+ int rx_curr_desc, rx_used_desc;
+ volatile titan_ge_rx_desc *rx_desc;
+
+ rx_curr_desc = titan_ge_port->rx_curr_desc_q;
+ rx_used_desc = titan_ge_port->rx_used_desc_q;
+
+ if (((rx_curr_desc + 1) % TITAN_GE_RX_QUEUE) == rx_used_desc)
+ return TITAN_ERROR;
+
+ rx_desc = &(titan_ge_port->rx_desc_area[rx_curr_desc]);
+
+ if (rx_desc->cmd_sts & TITAN_GE_RX_BUFFER_OWNED)
+ return TITAN_ERROR;
+
+ packet->skb = titan_ge_port->rx_skb[rx_curr_desc];
+ packet->len = (rx_desc->cmd_sts & 0x7fff);
+
+ /*
+ * At this point, we dont know if the checksumming
+ * actually helps relieve CPU. So, keep it for
+ * port 0 only
+ */
+ packet->checksum = ntohs((rx_desc->buffer & 0xffff0000) >> 16);
+ packet->cmd_sts = rx_desc->cmd_sts;
+
+ titan_ge_port->rx_curr_desc_q = (rx_curr_desc + 1) % TITAN_GE_RX_QUEUE;
+
+ /* Prefetch the next descriptor */
+ prefetch((const void *)
+ &titan_ge_port->rx_desc_area[titan_ge_port->rx_curr_desc_q + 1]);
+
+ return TITAN_OK;
+}
+
+/*
+ * Free the Tx queue of the used SKBs
+ */
+static int titan_ge_free_tx_queue(titan_ge_port_info *titan_ge_eth)
+{
+ unsigned long flags;
+
+ /* Take the lock */
+ spin_lock_irqsave(&(titan_ge_eth->lock), flags);
+
+ while (titan_ge_return_tx_desc(titan_ge_eth, titan_ge_eth->port_num) == 0)
+ if (titan_ge_eth->tx_ring_skbs != 1)
+ titan_ge_eth->tx_ring_skbs--;
+
+ spin_unlock_irqrestore(&titan_ge_eth->lock, flags);
+
+ return TITAN_OK;
+}
+
+/*
+ * Threshold beyond which we do the cleaning of
+ * Tx queue and new allocation for the Rx
+ * queue
+ */
+#define TX_THRESHOLD 4
+#define RX_THRESHOLD 10
+
+/*
+ * Receive the packets and send it to the kernel.
+ */
+static int titan_ge_receive_queue(struct net_device *netdev, unsigned int max)
+{
+ titan_ge_port_info *titan_ge_eth = netdev_priv(netdev);
+ unsigned int port_num = titan_ge_eth->port_num;
+ titan_ge_packet packet;
+ struct net_device_stats *stats;
+ struct sk_buff *skb;
+ unsigned long received_packets = 0;
+ unsigned int ack;
+
+ stats = &titan_ge_eth->stats;
+
+ while ((--max)
+ && (titan_ge_rx(netdev, port_num, titan_ge_eth, &packet) == TITAN_OK)) {
+ skb = (struct sk_buff *) packet.skb;
+
+ titan_ge_eth->rx_ring_skbs--;
+
+ if (--titan_ge_eth->rx_work_limit < 0)
+ break;
+ received_packets++;
+
+ stats->rx_packets++;
+ stats->rx_bytes += packet.len;
+
+ if ((packet.cmd_sts & TITAN_GE_RX_PERR) ||
+ (packet.cmd_sts & TITAN_GE_RX_OVERFLOW_ERROR) ||
+ (packet.cmd_sts & TITAN_GE_RX_TRUNC) ||
+ (packet.cmd_sts & TITAN_GE_RX_CRC_ERROR)) {
+ stats->rx_dropped++;
+ dev_kfree_skb_any(skb);
+
+ continue;
+ }
+ /*
+ * Either support fast path or slow path. Decision
+ * making can really slow down the performance. The
+ * idea is to cut down the number of checks and improve
+ * the fastpath.
+ */
+
+ skb_put(skb, packet.len - 2);
+
+ /*
+ * Increment data pointer by two since thats where
+ * the MAC starts
+ */
+ skb_reserve(skb, 2);
+ skb->protocol = eth_type_trans(skb, netdev);
+ netif_receive_skb(skb);
+
+ if (titan_ge_eth->rx_threshold > RX_THRESHOLD) {
+ ack = titan_ge_rx_task(netdev, titan_ge_eth);
+ TITAN_GE_WRITE((0x5048 + (port_num << 8)), ack);
+ titan_ge_eth->rx_threshold = 0;
+ } else
+ titan_ge_eth->rx_threshold++;
+
+ if (titan_ge_eth->tx_threshold > TX_THRESHOLD) {
+ titan_ge_eth->tx_threshold = 0;
+ titan_ge_free_tx_queue(titan_ge_eth);
+ }
+ else
+ titan_ge_eth->tx_threshold++;
+
+ }
+ return received_packets;
+}
+
+
+/*
+ * Enable the Rx side interrupts
+ */
+static void titan_ge_enable_int(unsigned int port_num,
+ titan_ge_port_info *titan_ge_eth,
+ struct net_device *netdev)
+{
+ unsigned long reg_data = TITAN_GE_READ(TITAN_GE_INTR_XDMA_IE);
+
+ if (port_num == 0)
+ reg_data |= 0x3;
+ if (port_num == 1)
+ reg_data |= 0x300;
+ if (port_num == 2)
+ reg_data |= 0x30000;
+
+ /* Re-enable interrupts */
+ TITAN_GE_WRITE(TITAN_GE_INTR_XDMA_IE, reg_data);
+}
+
+/*
+ * Main function to handle the polling for Rx side NAPI.
+ * Receive interrupts have been disabled at this point.
+ * The poll schedules the transmit followed by receive.
+ */
+static int titan_ge_poll(struct net_device *netdev, int *budget)
+{
+ titan_ge_port_info *titan_ge_eth = netdev_priv(netdev);
+ int port_num = titan_ge_eth->port_num;
+ int work_done = 0;
+ unsigned long flags, status;
+
+ titan_ge_eth->rx_work_limit = *budget;
+ if (titan_ge_eth->rx_work_limit > netdev->quota)
+ titan_ge_eth->rx_work_limit = netdev->quota;
+
+ do {
+ /* Do the transmit cleaning work here */
+ titan_ge_free_tx_queue(titan_ge_eth);
+
+ /* Ack the Rx interrupts */
+ if (port_num == 0)
+ TITAN_GE_WRITE(TITAN_GE_INTR_XDMA_CORE_A, 0x3);
+ if (port_num == 1)
+ TITAN_GE_WRITE(TITAN_GE_INTR_XDMA_CORE_A, 0x300);
+ if (port_num == 2)
+ TITAN_GE_WRITE(TITAN_GE_INTR_XDMA_CORE_A, 0x30000);
+
+ work_done += titan_ge_receive_queue(netdev, 0);
+
+ /* Out of quota and there is work to be done */
+ if (titan_ge_eth->rx_work_limit < 0)
+ goto not_done;
+
+ /* Receive alloc_skb could lead to OOM */
+ if (oom_flag == 1) {
+ oom_flag = 0;
+ goto oom;
+ }
+
+ status = TITAN_GE_READ(TITAN_GE_INTR_XDMA_CORE_A);
+ } while (status & 0x30300);
+
+ /* If we are here, then no more interrupts to process */
+ goto done;
+
+not_done:
+ *budget -= work_done;
+ netdev->quota -= work_done;
+ return 1;
+
+oom:
+ printk(KERN_ERR "OOM \n");
+ netif_rx_complete(netdev);
+ return 0;
+
+done:
+ /*
+ * No more packets on the poll list. Turn the interrupts
+ * back on and we should be able to catch the new
+ * packets in the interrupt handler
+ */
+ if (!work_done)
+ work_done = 1;
+
+ *budget -= work_done;
+ netdev->quota -= work_done;
+
+ spin_lock_irqsave(&titan_ge_eth->lock, flags);
+
+ /* Remove us from the poll list */
+ netif_rx_complete(netdev);
+
+ /* Re-enable interrupts */
+ titan_ge_enable_int(port_num, titan_ge_eth, netdev);
+
+ spin_unlock_irqrestore(&titan_ge_eth->lock, flags);
+
+ return 0;
+}
+
+/*
+ * Close the network device
+ */
+int titan_ge_stop(struct net_device *netdev)
+{
+ titan_ge_port_info *titan_ge_eth = netdev_priv(netdev);
+
+ spin_lock_irq(&(titan_ge_eth->lock));
+ titan_ge_eth_stop(netdev);
+ free_irq(netdev->irq, netdev);
+ spin_unlock_irq(&titan_ge_eth->lock);
+
+ return TITAN_OK;
+}
+
+/*
+ * Free the Tx ring
+ */
+static void titan_ge_free_tx_rings(struct net_device *netdev)
+{
+ titan_ge_port_info *titan_ge_eth = netdev_priv(netdev);
+ unsigned int port_num = titan_ge_eth->port_num;
+ unsigned int curr;
+ unsigned long reg_data;
+
+ /* Stop the Tx DMA */
+ reg_data = TITAN_GE_READ(TITAN_GE_CHANNEL0_CONFIG +
+ (port_num << 8));
+ reg_data |= 0xc0000000;
+ TITAN_GE_WRITE((TITAN_GE_CHANNEL0_CONFIG +
+ (port_num << 8)), reg_data);
+
+ /* Disable the TMAC */
+ reg_data = TITAN_GE_READ(TITAN_GE_TMAC_CONFIG_1 +
+ (port_num << 12));
+ reg_data &= ~(0x00000001);
+ TITAN_GE_WRITE((TITAN_GE_TMAC_CONFIG_1 +
+ (port_num << 12)), reg_data);
+
+ for (curr = 0;
+ (titan_ge_eth->tx_ring_skbs) && (curr < TITAN_GE_TX_QUEUE);
+ curr++) {
+ if (titan_ge_eth->tx_skb[curr]) {
+ dev_kfree_skb(titan_ge_eth->tx_skb[curr]);
+ titan_ge_eth->tx_ring_skbs--;
+ }
+ }
+
+ if (titan_ge_eth->tx_ring_skbs != 0)
+ printk
+ ("%s: Error on Tx descriptor free - could not free %d"
+ " descriptors\n", netdev->name,
+ titan_ge_eth->tx_ring_skbs);
+
+#ifndef TITAN_RX_RING_IN_SRAM
+ dma_free_coherent(&titan_ge_device[port_num]->dev,
+ titan_ge_eth->tx_desc_area_size,
+ (void *) titan_ge_eth->tx_desc_area,
+ titan_ge_eth->tx_dma);
+#endif
+}
+
+/*
+ * Free the Rx ring
+ */
+static void titan_ge_free_rx_rings(struct net_device *netdev)
+{
+ titan_ge_port_info *titan_ge_eth = netdev_priv(netdev);
+ unsigned int port_num = titan_ge_eth->port_num;
+ unsigned int curr;
+ unsigned long reg_data;
+
+ /* Stop the Rx DMA */
+ reg_data = TITAN_GE_READ(TITAN_GE_CHANNEL0_CONFIG +
+ (port_num << 8));
+ reg_data |= 0x000c0000;
+ TITAN_GE_WRITE((TITAN_GE_CHANNEL0_CONFIG +
+ (port_num << 8)), reg_data);
+
+ /* Disable the RMAC */
+ reg_data = TITAN_GE_READ(TITAN_GE_RMAC_CONFIG_1 +
+ (port_num << 12));
+ reg_data &= ~(0x00000001);
+ TITAN_GE_WRITE((TITAN_GE_RMAC_CONFIG_1 +
+ (port_num << 12)), reg_data);
+
+ for (curr = 0;
+ titan_ge_eth->rx_ring_skbs && (curr < TITAN_GE_RX_QUEUE);
+ curr++) {
+ if (titan_ge_eth->rx_skb[curr]) {
+ dev_kfree_skb(titan_ge_eth->rx_skb[curr]);
+ titan_ge_eth->rx_ring_skbs--;
+ }
+ }
+
+ if (titan_ge_eth->rx_ring_skbs != 0)
+ printk(KERN_ERR
+ "%s: Error in freeing Rx Ring. %d skb's still"
+ " stuck in RX Ring - ignoring them\n", netdev->name,
+ titan_ge_eth->rx_ring_skbs);
+
+#ifndef TITAN_RX_RING_IN_SRAM
+ dma_free_coherent(&titan_ge_device[port_num]->dev,
+ titan_ge_eth->rx_desc_area_size,
+ (void *) titan_ge_eth->rx_desc_area,
+ titan_ge_eth->rx_dma);
+#endif
+}
+
+/*
+ * Actually does the stop of the Ethernet device
+ */
+static void titan_ge_eth_stop(struct net_device *netdev)
+{
+ titan_ge_port_info *titan_ge_eth = netdev_priv(netdev);
+
+ netif_stop_queue(netdev);
+
+ titan_ge_port_reset(titan_ge_eth->port_num);
+
+ titan_ge_free_tx_rings(netdev);
+ titan_ge_free_rx_rings(netdev);
+
+ /* Disable the Tx and Rx Interrupts for all channels */
+ TITAN_GE_WRITE(TITAN_GE_INTR_XDMA_IE, 0x0);
+}
+
+/*
+ * Update the MAC address. Note that we have to write the
+ * address in three station registers, 16 bits each. And this
+ * has to be done for TMAC and RMAC
+ */
+static void titan_ge_update_mac_address(struct net_device *netdev)
+{
+ titan_ge_port_info *titan_ge_eth = netdev_priv(netdev);
+ unsigned int port_num = titan_ge_eth->port_num;
+ u8 p_addr[6];
+
+ memcpy(titan_ge_eth->port_mac_addr, netdev->dev_addr, 6);
+ memcpy(p_addr, netdev->dev_addr, 6);
+
+ /* Update the Address Filtering Match tables */
+ titan_ge_update_afx(titan_ge_eth);
+
+ printk("Station MAC : %d %d %d %d %d %d \n",
+ p_addr[5], p_addr[4], p_addr[3],
+ p_addr[2], p_addr[1], p_addr[0]);
+
+ /* Set the MAC address here for TMAC and RMAC */
+ TITAN_GE_WRITE((TITAN_GE_TMAC_STATION_HI + (port_num << 12)),
+ ((p_addr[5] << 8) | p_addr[4]));
+ TITAN_GE_WRITE((TITAN_GE_TMAC_STATION_MID + (port_num << 12)),
+ ((p_addr[3] << 8) | p_addr[2]));
+ TITAN_GE_WRITE((TITAN_GE_TMAC_STATION_LOW + (port_num << 12)),
+ ((p_addr[1] << 8) | p_addr[0]));
+
+ TITAN_GE_WRITE((TITAN_GE_RMAC_STATION_HI + (port_num << 12)),
+ ((p_addr[5] << 8) | p_addr[4]));
+ TITAN_GE_WRITE((TITAN_GE_RMAC_STATION_MID + (port_num << 12)),
+ ((p_addr[3] << 8) | p_addr[2]));
+ TITAN_GE_WRITE((TITAN_GE_RMAC_STATION_LOW + (port_num << 12)),
+ ((p_addr[1] << 8) | p_addr[0]));
+}
+
+/*
+ * Set the MAC address of the Ethernet device
+ */
+static int titan_ge_set_mac_address(struct net_device *dev, void *addr)
+{
+ titan_ge_port_info *tp = netdev_priv(dev);
+ struct sockaddr *sa = addr;
+
+ memcpy(dev->dev_addr, sa->sa_data, dev->addr_len);
+
+ spin_lock_irq(&tp->lock);
+ titan_ge_update_mac_address(dev);
+ spin_unlock_irq(&tp->lock);
+
+ return 0;
+}
+
+/*
+ * Get the Ethernet device stats
+ */
+static struct net_device_stats *titan_ge_get_stats(struct net_device *netdev)
+{
+ titan_ge_port_info *titan_ge_eth = netdev_priv(netdev);
+
+ return &titan_ge_eth->stats;
+}
+
+/*
+ * Initialize the Rx descriptor ring for the Titan Ge
+ */
+static int titan_ge_init_rx_desc_ring(titan_ge_port_info * titan_eth_port,
+ int rx_desc_num,
+ int rx_buff_size,
+ unsigned long rx_desc_base_addr,
+ unsigned long rx_buff_base_addr,
+ unsigned long rx_dma)
+{
+ volatile titan_ge_rx_desc *rx_desc;
+ unsigned long buffer_addr;
+ int index;
+ unsigned long titan_ge_rx_desc_bus = rx_dma;
+
+ buffer_addr = rx_buff_base_addr;
+ rx_desc = (titan_ge_rx_desc *) rx_desc_base_addr;
+
+ /* Check alignment */
+ if (rx_buff_base_addr & 0xF)
+ return 0;
+
+ /* Check Rx buffer size */
+ if ((rx_buff_size < 8) || (rx_buff_size > TITAN_GE_MAX_RX_BUFFER))
+ return 0;
+
+ /* 64-bit alignment
+ if ((rx_buff_base_addr + rx_buff_size) & 0x7)
+ return 0; */
+
+ /* Initialize the Rx desc ring */
+ for (index = 0; index < rx_desc_num; index++) {
+ titan_ge_rx_desc_bus += sizeof(titan_ge_rx_desc);
+ rx_desc[index].cmd_sts = 0;
+ rx_desc[index].buffer_addr = buffer_addr;
+ titan_eth_port->rx_skb[index] = NULL;
+ buffer_addr += rx_buff_size;
+ }
+
+ titan_eth_port->rx_curr_desc_q = 0;
+ titan_eth_port->rx_used_desc_q = 0;
+
+ titan_eth_port->rx_desc_area = (titan_ge_rx_desc *) rx_desc_base_addr;
+ titan_eth_port->rx_desc_area_size =
+ rx_desc_num * sizeof(titan_ge_rx_desc);
+
+ titan_eth_port->rx_dma = rx_dma;
+
+ return TITAN_OK;
+}
+
+/*
+ * Initialize the Tx descriptor ring. Descriptors in the SRAM
+ */
+static int titan_ge_init_tx_desc_ring(titan_ge_port_info * titan_ge_port,
+ int tx_desc_num,
+ unsigned long tx_desc_base_addr,
+ unsigned long tx_dma)
+{
+ titan_ge_tx_desc *tx_desc;
+ int index;
+ unsigned long titan_ge_tx_desc_bus = tx_dma;
+
+ if (tx_desc_base_addr & 0xF)
+ return 0;
+
+ tx_desc = (titan_ge_tx_desc *) tx_desc_base_addr;
+
+ for (index = 0; index < tx_desc_num; index++) {
+ titan_ge_port->tx_dma_array[index] =
+ (dma_addr_t) titan_ge_tx_desc_bus;
+ titan_ge_tx_desc_bus += sizeof(titan_ge_tx_desc);
+ tx_desc[index].cmd_sts = 0x0000;
+ tx_desc[index].buffer_len = 0;
+ tx_desc[index].buffer_addr = 0x00000000;
+ titan_ge_port->tx_skb[index] = NULL;
+ }
+
+ titan_ge_port->tx_curr_desc_q = 0;
+ titan_ge_port->tx_used_desc_q = 0;
+
+ titan_ge_port->tx_desc_area = (titan_ge_tx_desc *) tx_desc_base_addr;
+ titan_ge_port->tx_desc_area_size =
+ tx_desc_num * sizeof(titan_ge_tx_desc);
+
+ titan_ge_port->tx_dma = tx_dma;
+ return TITAN_OK;
+}
+
+/*
+ * Initialize the device as an Ethernet device
+ */
+static int __init titan_ge_probe(struct device *device)
+{
+ titan_ge_port_info *titan_ge_eth;
+ struct net_device *netdev;
+ int port = to_platform_device(device)->id;
+ int err;
+
+ netdev = alloc_etherdev(sizeof(titan_ge_port_info));
+ if (!netdev) {
+ err = -ENODEV;
+ goto out;
+ }
+
+ netdev->open = titan_ge_open;
+ netdev->stop = titan_ge_stop;
+ netdev->hard_start_xmit = titan_ge_start_xmit;
+ netdev->get_stats = titan_ge_get_stats;
+ netdev->set_multicast_list = titan_ge_set_multi;
+ netdev->set_mac_address = titan_ge_set_mac_address;
+
+ /* Tx timeout */
+ netdev->tx_timeout = titan_ge_tx_timeout;
+ netdev->watchdog_timeo = 2 * HZ;
+
+ /* Set these to very high values */
+ netdev->poll = titan_ge_poll;
+ netdev->weight = 64;
+
+ netdev->tx_queue_len = TITAN_GE_TX_QUEUE;
+ netif_carrier_off(netdev);
+ netdev->base_addr = 0;
+
+ netdev->change_mtu = titan_ge_change_mtu;
+
+ titan_ge_eth = netdev_priv(netdev);
+ /* Allocation of memory for the driver structures */
+
+ titan_ge_eth->port_num = port;
+
+ /* Configure the Tx timeout handler */
+ INIT_WORK(&titan_ge_eth->tx_timeout_task,
+ (void (*)(void *)) titan_ge_tx_timeout_task, netdev);
+
+ spin_lock_init(&titan_ge_eth->lock);
+
+ /* set MAC addresses */
+ memcpy(netdev->dev_addr, titan_ge_mac_addr_base, 6);
+ netdev->dev_addr[5] += port;
+
+ err = register_netdev(netdev);
+
+ if (err)
+ goto out_free_netdev;
+
+ printk(KERN_NOTICE
+ "%s: port %d with MAC address %02x:%02x:%02x:%02x:%02x:%02x\n",
+ netdev->name, port, netdev->dev_addr[0],
+ netdev->dev_addr[1], netdev->dev_addr[2],
+ netdev->dev_addr[3], netdev->dev_addr[4],
+ netdev->dev_addr[5]);
+
+ printk(KERN_NOTICE "Rx NAPI supported, Tx Coalescing ON \n");
+
+ return 0;
+
+out_free_netdev:
+ kfree(netdev);
+
+out:
+ return err;
+}
+
+static void __devexit titan_device_remove(struct device *device)
+{
+}
+
+/*
+ * Reset the Ethernet port
+ */
+static void titan_ge_port_reset(unsigned int port_num)
+{
+ unsigned int reg_data;
+
+ /* Stop the Tx port activity */
+ reg_data = TITAN_GE_READ(TITAN_GE_TMAC_CONFIG_1 +
+ (port_num << 12));
+ reg_data &= ~(0x0001);
+ TITAN_GE_WRITE((TITAN_GE_TMAC_CONFIG_1 +
+ (port_num << 12)), reg_data);
+
+ /* Stop the Rx port activity */
+ reg_data = TITAN_GE_READ(TITAN_GE_RMAC_CONFIG_1 +
+ (port_num << 12));
+ reg_data &= ~(0x0001);
+ TITAN_GE_WRITE((TITAN_GE_RMAC_CONFIG_1 +
+ (port_num << 12)), reg_data);
+
+ return;
+}
+
+/*
+ * Return the Tx desc after use by the XDMA
+ */
+static int titan_ge_return_tx_desc(titan_ge_port_info * titan_ge_eth, int port)
+{
+ int tx_desc_used;
+ struct sk_buff *skb;
+
+ tx_desc_used = titan_ge_eth->tx_used_desc_q;
+
+ /* return right away */
+ if (tx_desc_used == titan_ge_eth->tx_curr_desc_q)
+ return TITAN_ERROR;
+
+ /* Now the critical stuff */
+ skb = titan_ge_eth->tx_skb[tx_desc_used];
+
+ dev_kfree_skb_any(skb);
+
+ titan_ge_eth->tx_skb[tx_desc_used] = NULL;
+ titan_ge_eth->tx_used_desc_q =
+ (tx_desc_used + 1) % TITAN_GE_TX_QUEUE;
+
+ return 0;
+}
+
+/*
+ * Coalescing for the Tx path
+ */
+static unsigned long titan_ge_tx_coal(unsigned long delay, int port)
+{
+ unsigned long rx_delay;
+
+ rx_delay = TITAN_GE_READ(TITAN_GE_INT_COALESCING);
+ delay = (delay << 16) | rx_delay;
+
+ TITAN_GE_WRITE(TITAN_GE_INT_COALESCING, delay);
+ TITAN_GE_WRITE(0x5038, delay);
+
+ return delay;
+}
+
+static struct device_driver titan_soc_driver = {
+ .name = titan_string,
+ .bus = &platform_bus_type,
+ .probe = titan_ge_probe,
+ .remove = __devexit_p(titan_device_remove),
+};
+
+static void titan_platform_release (struct device *device)
+{
+ struct platform_device *pldev;
+
+ /* free device */
+ pldev = to_platform_device (device);
+ kfree (pldev);
+}
+
+/*
+ * Register the Titan GE with the kernel
+ */
+static int __init titan_ge_init_module(void)
+{
+ struct platform_device *pldev;
+ unsigned int version, device;
+ int i;
+
+ printk(KERN_NOTICE
+ "PMC-Sierra TITAN 10/100/1000 Ethernet Driver \n");
+
+ titan_ge_base = (unsigned long) ioremap(TITAN_GE_BASE, TITAN_GE_SIZE);
+ if (!titan_ge_base) {
+ printk("Mapping Titan GE failed\n");
+ goto out;
+ }
+
+ device = TITAN_GE_READ(TITAN_GE_DEVICE_ID);
+ version = (device & 0x000f0000) >> 16;
+ device &= 0x0000ffff;
+
+ printk(KERN_NOTICE "Device Id : %x, Version : %x \n", device, version);
+
+#ifdef TITAN_RX_RING_IN_SRAM
+ titan_ge_sram = (unsigned long) ioremap(TITAN_SRAM_BASE,
+ TITAN_SRAM_SIZE);
+ if (!titan_ge_sram) {
+ printk("Mapping Titan SRAM failed\n");
+ goto out_unmap_ge;
+ }
+#endif
+
+ if (driver_register(&titan_soc_driver)) {
+ printk(KERN_ERR "Driver registration failed\n");
+ goto out_unmap_sram;
+ }
+
+ for (i = 0; i < 3; i++) {
+ titan_ge_device[i] = NULL;
+
+ if (!(pldev = kmalloc (sizeof (*pldev), GFP_KERNEL)))
+ continue;
+
+ memset (pldev, 0, sizeof (*pldev));
+ pldev->name = titan_string;
+ pldev->id = i;
+ pldev->dev.release = titan_platform_release;
+ titan_ge_device[i] = pldev;
+
+ if (platform_device_register (pldev)) {
+ kfree (pldev);
+ titan_ge_device[i] = NULL;
+ continue;
+ }
+
+ if (!pldev->dev.driver) {
+ /*
+ * The driver was not bound to this device, there was
+ * no hardware at this address. Unregister it, as the
+ * release fuction will take care of freeing the
+ * allocated structure
+ */
+ titan_ge_device[i] = NULL;
+ platform_device_unregister (pldev);
+ }
+ }
+
+ return 0;
+
+out_unmap_sram:
+ iounmap((void *)titan_ge_sram);
+
+out_unmap_ge:
+ iounmap((void *)titan_ge_base);
+
+out:
+ return -ENOMEM;
+}
+
+/*
+ * Unregister the Titan GE from the kernel
+ */
+static void __exit titan_ge_cleanup_module(void)
+{
+ int i;
+
+ driver_unregister(&titan_soc_driver);
+
+ for (i = 0; i < 3; i++) {
+ if (titan_ge_device[i]) {
+ platform_device_unregister (titan_ge_device[i]);
+ titan_ge_device[i] = NULL;
+ }
+ }
+
+ iounmap((void *)titan_ge_sram);
+ iounmap((void *)titan_ge_base);
+}
+
+MODULE_AUTHOR("Manish Lachwani <lachwani@pmc-sierra.com>");
+MODULE_DESCRIPTION("Titan GE Ethernet driver");
+MODULE_LICENSE("GPL");
+
+module_init(titan_ge_init_module);
+module_exit(titan_ge_cleanup_module);
diff --git a/drivers/net/titan_ge.h b/drivers/net/titan_ge.h
new file mode 100644
index 0000000..3719f78
--- /dev/null
+++ b/drivers/net/titan_ge.h
@@ -0,0 +1,415 @@
+#ifndef _TITAN_GE_H_
+#define _TITAN_GE_H_
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/spinlock.h>
+#include <asm/byteorder.h>
+
+/*
+ * These functions should be later moved to a more generic location since there
+ * will be others accessing it also
+ */
+
+/*
+ * This is the way it works: LKB5 Base is at 0x0128. TITAN_BASE is defined in
+ * include/asm/titan_dep.h. TITAN_GE_BASE is the value in the TITAN_GE_LKB5
+ * register.
+ */
+
+#define TITAN_GE_BASE 0xfe000000UL
+#define TITAN_GE_SIZE 0x10000UL
+
+extern unsigned long titan_ge_base;
+
+#define TITAN_GE_WRITE(offset, data) \
+ *(volatile u32 *)(titan_ge_base + (offset)) = (data)
+
+#define TITAN_GE_READ(offset) *(volatile u32 *)(titan_ge_base + (offset))
+
+#ifndef msec_delay
+#define msec_delay(x) do { if(in_interrupt()) { \
+ /* Don't mdelay in interrupt context! */ \
+ BUG(); \
+ } else { \
+ set_current_state(TASK_UNINTERRUPTIBLE); \
+ schedule_timeout((x * HZ)/1000); \
+ } } while(0)
+#endif
+
+#define TITAN_GE_PORT_0
+
+#define TITAN_SRAM_BASE ((OCD_READ(RM9000x2_OCD_LKB13) & ~1) << 4)
+#define TITAN_SRAM_SIZE 0x2000UL
+
+/*
+ * We may need these constants
+ */
+#define TITAN_BIT0 0x00000001
+#define TITAN_BIT1 0x00000002
+#define TITAN_BIT2 0x00000004
+#define TITAN_BIT3 0x00000008
+#define TITAN_BIT4 0x00000010
+#define TITAN_BIT5 0x00000020
+#define TITAN_BIT6 0x00000040
+#define TITAN_BIT7 0x00000080
+#define TITAN_BIT8 0x00000100
+#define TITAN_BIT9 0x00000200
+#define TITAN_BIT10 0x00000400
+#define TITAN_BIT11 0x00000800
+#define TITAN_BIT12 0x00001000
+#define TITAN_BIT13 0x00002000
+#define TITAN_BIT14 0x00004000
+#define TITAN_BIT15 0x00008000
+#define TITAN_BIT16 0x00010000
+#define TITAN_BIT17 0x00020000
+#define TITAN_BIT18 0x00040000
+#define TITAN_BIT19 0x00080000
+#define TITAN_BIT20 0x00100000
+#define TITAN_BIT21 0x00200000
+#define TITAN_BIT22 0x00400000
+#define TITAN_BIT23 0x00800000
+#define TITAN_BIT24 0x01000000
+#define TITAN_BIT25 0x02000000
+#define TITAN_BIT26 0x04000000
+#define TITAN_BIT27 0x08000000
+#define TITAN_BIT28 0x10000000
+#define TITAN_BIT29 0x20000000
+#define TITAN_BIT30 0x40000000
+#define TITAN_BIT31 0x80000000
+
+/* Flow Control */
+#define TITAN_GE_FC_NONE 0x0
+#define TITAN_GE_FC_FULL 0x1
+#define TITAN_GE_FC_TX_PAUSE 0x2
+#define TITAN_GE_FC_RX_PAUSE 0x3
+
+/* Duplex Settings */
+#define TITAN_GE_FULL_DUPLEX 0x1
+#define TITAN_GE_HALF_DUPLEX 0x2
+
+/* Speed settings */
+#define TITAN_GE_SPEED_1000 0x1
+#define TITAN_GE_SPEED_100 0x2
+#define TITAN_GE_SPEED_10 0x3
+
+/* Debugging info only */
+#undef TITAN_DEBUG
+
+/* Keep the rings in the Titan's SSRAM */
+#define TITAN_RX_RING_IN_SRAM
+
+#ifdef CONFIG_64BIT
+#define TITAN_GE_IE_MASK 0xfffffffffb001b64
+#define TITAN_GE_IE_STATUS 0xfffffffffb001b60
+#else
+#define TITAN_GE_IE_MASK 0xfb001b64
+#define TITAN_GE_IE_STATUS 0xfb001b60
+#endif
+
+/* Support for Jumbo Frames */
+#undef TITAN_GE_JUMBO_FRAMES
+
+/* Rx buffer size */
+#ifdef TITAN_GE_JUMBO_FRAMES
+#define TITAN_GE_JUMBO_BUFSIZE 9080
+#else
+#define TITAN_GE_STD_BUFSIZE 1580
+#endif
+
+/*
+ * Tx and Rx Interrupt Coalescing parameter. These values are
+ * for 1 Ghz processor. Rx coalescing can be taken care of
+ * by NAPI. NAPI is adaptive and hence useful. Tx coalescing
+ * is not adaptive. Hence, these values need to be adjusted
+ * based on load, CPU speed etc.
+ */
+#define TITAN_GE_RX_COAL 150
+#define TITAN_GE_TX_COAL 300
+
+#if defined(__BIG_ENDIAN)
+
+/* Define the Rx descriptor */
+typedef struct eth_rx_desc {
+ u32 reserved; /* Unused */
+ u32 buffer_addr; /* CPU buffer address */
+ u32 cmd_sts; /* Command and Status */
+ u32 buffer; /* XDMA buffer address */
+} titan_ge_rx_desc;
+
+/* Define the Tx descriptor */
+typedef struct eth_tx_desc {
+ u16 cmd_sts; /* Command, Status and Buffer count */
+ u16 buffer_len; /* Length of the buffer */
+ u32 buffer_addr; /* Physical address of the buffer */
+} titan_ge_tx_desc;
+
+#elif defined(__LITTLE_ENDIAN)
+
+/* Define the Rx descriptor */
+typedef struct eth_rx_desc {
+ u32 buffer_addr; /* CPU buffer address */
+ u32 reserved; /* Unused */
+ u32 buffer; /* XDMA buffer address */
+ u32 cmd_sts; /* Command and Status */
+} titan_ge_rx_desc;
+
+/* Define the Tx descriptor */
+typedef struct eth_tx_desc {
+ u32 buffer_addr; /* Physical address of the buffer */
+ u16 buffer_len; /* Length of the buffer */
+ u16 cmd_sts; /* Command, Status and Buffer count */
+} titan_ge_tx_desc;
+#endif
+
+/* Default Tx Queue Size */
+#define TITAN_GE_TX_QUEUE 128
+#define TITAN_TX_RING_BYTES (TITAN_GE_TX_QUEUE * sizeof(struct eth_tx_desc))
+
+/* Default Rx Queue Size */
+#define TITAN_GE_RX_QUEUE 64
+#define TITAN_RX_RING_BYTES (TITAN_GE_RX_QUEUE * sizeof(struct eth_rx_desc))
+
+/* Packet Structure */
+typedef struct _pkt_info {
+ unsigned int len;
+ unsigned int cmd_sts;
+ unsigned int buffer;
+ struct sk_buff *skb;
+ unsigned int checksum;
+} titan_ge_packet;
+
+
+#define PHYS_CNT 3
+
+/* Titan Port specific data structure */
+typedef struct _eth_port_ctrl {
+ unsigned int port_num;
+ u8 port_mac_addr[6];
+
+ /* Rx descriptor pointers */
+ int rx_curr_desc_q, rx_used_desc_q;
+
+ /* Tx descriptor pointers */
+ int tx_curr_desc_q, tx_used_desc_q;
+
+ /* Rx descriptor area */
+ volatile titan_ge_rx_desc *rx_desc_area;
+ unsigned int rx_desc_area_size;
+ struct sk_buff* rx_skb[TITAN_GE_RX_QUEUE];
+
+ /* Tx Descriptor area */
+ volatile titan_ge_tx_desc *tx_desc_area;
+ unsigned int tx_desc_area_size;
+ struct sk_buff* tx_skb[TITAN_GE_TX_QUEUE];
+
+ /* Timeout task */
+ struct work_struct tx_timeout_task;
+
+ /* DMA structures and handles */
+ dma_addr_t tx_dma;
+ dma_addr_t rx_dma;
+ dma_addr_t tx_dma_array[TITAN_GE_TX_QUEUE];
+
+ /* Device lock */
+ spinlock_t lock;
+
+ unsigned int tx_ring_skbs;
+ unsigned int rx_ring_size;
+ unsigned int tx_ring_size;
+ unsigned int rx_ring_skbs;
+
+ struct net_device_stats stats;
+
+ /* Tx and Rx coalescing */
+ unsigned long rx_int_coal;
+ unsigned long tx_int_coal;
+
+ /* Threshold for replenishing the Rx and Tx rings */
+ unsigned int tx_threshold;
+ unsigned int rx_threshold;
+
+ /* NAPI work limit */
+ unsigned int rx_work_limit;
+} titan_ge_port_info;
+
+/* Titan specific constants */
+#define TITAN_ETH_PORT_IRQ 3
+
+/* Max Rx buffer */
+#define TITAN_GE_MAX_RX_BUFFER 65536
+
+/* Tx and Rx Error */
+#define TITAN_GE_ERROR
+
+/* Rx Descriptor Command and Status */
+
+#define TITAN_GE_RX_CRC_ERROR TITAN_BIT27 /* crc error */
+#define TITAN_GE_RX_OVERFLOW_ERROR TITAN_BIT15 /* overflow */
+#define TITAN_GE_RX_BUFFER_OWNED TITAN_BIT21 /* buffer ownership */
+#define TITAN_GE_RX_STP TITAN_BIT31 /* start of packet */
+#define TITAN_GE_RX_BAM TITAN_BIT30 /* broadcast address match */
+#define TITAN_GE_RX_PAM TITAN_BIT28 /* physical address match */
+#define TITAN_GE_RX_LAFM TITAN_BIT29 /* logical address filter match */
+#define TITAN_GE_RX_VLAN TITAN_BIT26 /* virtual lans */
+#define TITAN_GE_RX_PERR TITAN_BIT19 /* packet error */
+#define TITAN_GE_RX_TRUNC TITAN_BIT20 /* packet size greater than 32 buffers */
+
+/* Tx Descriptor Command */
+#define TITAN_GE_TX_BUFFER_OWNED TITAN_BIT5 /* buffer ownership */
+#define TITAN_GE_TX_ENABLE_INTERRUPT TITAN_BIT15 /* Interrupt Enable */
+
+/* Return Status */
+#define TITAN_OK 0x1 /* Good Status */
+#define TITAN_ERROR 0x2 /* Error Status */
+
+/* MIB specific register offset */
+#define TITAN_GE_MSTATX_STATS_BASE_LOW 0x0800 /* MSTATX COUNTL[15:0] */
+#define TITAN_GE_MSTATX_STATS_BASE_MID 0x0804 /* MSTATX COUNTM[15:0] */
+#define TITAN_GE_MSTATX_STATS_BASE_HI 0x0808 /* MSTATX COUNTH[7:0] */
+#define TITAN_GE_MSTATX_CONTROL 0x0828 /* MSTATX Control */
+#define TITAN_GE_MSTATX_VARIABLE_SELECT 0x082C /* MSTATX Variable Select */
+
+/* MIB counter offsets, add to the TITAN_GE_MSTATX_STATS_BASE_XXX */
+#define TITAN_GE_MSTATX_RXFRAMESOK 0x0040
+#define TITAN_GE_MSTATX_RXOCTETSOK 0x0050
+#define TITAN_GE_MSTATX_RXFRAMES 0x0060
+#define TITAN_GE_MSTATX_RXOCTETS 0x0070
+#define TITAN_GE_MSTATX_RXUNICASTFRAMESOK 0x0080
+#define TITAN_GE_MSTATX_RXBROADCASTFRAMESOK 0x0090
+#define TITAN_GE_MSTATX_RXMULTICASTFRAMESOK 0x00A0
+#define TITAN_GE_MSTATX_RXTAGGEDFRAMESOK 0x00B0
+#define TITAN_GE_MSTATX_RXMACPAUSECONTROLFRAMESOK 0x00C0
+#define TITAN_GE_MSTATX_RXMACCONTROLFRAMESOK 0x00D0
+#define TITAN_GE_MSTATX_RXFCSERROR 0x00E0
+#define TITAN_GE_MSTATX_RXALIGNMENTERROR 0x00F0
+#define TITAN_GE_MSTATX_RXSYMBOLERROR 0x0100
+#define TITAN_GE_MSTATX_RXLAYER1ERROR 0x0110
+#define TITAN_GE_MSTATX_RXINRANGELENGTHERROR 0x0120
+#define TITAN_GE_MSTATX_RXLONGLENGTHERROR 0x0130
+#define TITAN_GE_MSTATX_RXLONGLENGTHCRCERROR 0x0140
+#define TITAN_GE_MSTATX_RXSHORTLENGTHERROR 0x0150
+#define TITAN_GE_MSTATX_RXSHORTLLENGTHCRCERROR 0x0160
+#define TITAN_GE_MSTATX_RXFRAMES64OCTETS 0x0170
+#define TITAN_GE_MSTATX_RXFRAMES65TO127OCTETS 0x0180
+#define TITAN_GE_MSTATX_RXFRAMES128TO255OCTETS 0x0190
+#define TITAN_GE_MSTATX_RXFRAMES256TO511OCTETS 0x01A0
+#define TITAN_GE_MSTATX_RXFRAMES512TO1023OCTETS 0x01B0
+#define TITAN_GE_MSTATX_RXFRAMES1024TO1518OCTETS 0x01C0
+#define TITAN_GE_MSTATX_RXFRAMES1519TOMAXSIZE 0x01D0
+#define TITAN_GE_MSTATX_RXSTATIONADDRESSFILTERED 0x01E0
+#define TITAN_GE_MSTATX_RXVARIABLE 0x01F0
+#define TITAN_GE_MSTATX_GENERICADDRESSFILTERED 0x0200
+#define TITAN_GE_MSTATX_UNICASTFILTERED 0x0210
+#define TITAN_GE_MSTATX_MULTICASTFILTERED 0x0220
+#define TITAN_GE_MSTATX_BROADCASTFILTERED 0x0230
+#define TITAN_GE_MSTATX_HASHFILTERED 0x0240
+#define TITAN_GE_MSTATX_TXFRAMESOK 0x0250
+#define TITAN_GE_MSTATX_TXOCTETSOK 0x0260
+#define TITAN_GE_MSTATX_TXOCTETS 0x0270
+#define TITAN_GE_MSTATX_TXTAGGEDFRAMESOK 0x0280
+#define TITAN_GE_MSTATX_TXMACPAUSECONTROLFRAMESOK 0x0290
+#define TITAN_GE_MSTATX_TXFCSERROR 0x02A0
+#define TITAN_GE_MSTATX_TXSHORTLENGTHERROR 0x02B0
+#define TITAN_GE_MSTATX_TXLONGLENGTHERROR 0x02C0
+#define TITAN_GE_MSTATX_TXSYSTEMERROR 0x02D0
+#define TITAN_GE_MSTATX_TXMACERROR 0x02E0
+#define TITAN_GE_MSTATX_TXCARRIERSENSEERROR 0x02F0
+#define TITAN_GE_MSTATX_TXSQETESTERROR 0x0300
+#define TITAN_GE_MSTATX_TXUNICASTFRAMESOK 0x0310
+#define TITAN_GE_MSTATX_TXBROADCASTFRAMESOK 0x0320
+#define TITAN_GE_MSTATX_TXMULTICASTFRAMESOK 0x0330
+#define TITAN_GE_MSTATX_TXUNICASTFRAMESATTEMPTED 0x0340
+#define TITAN_GE_MSTATX_TXBROADCASTFRAMESATTEMPTED 0x0350
+#define TITAN_GE_MSTATX_TXMULTICASTFRAMESATTEMPTED 0x0360
+#define TITAN_GE_MSTATX_TXFRAMES64OCTETS 0x0370
+#define TITAN_GE_MSTATX_TXFRAMES65TO127OCTETS 0x0380
+#define TITAN_GE_MSTATX_TXFRAMES128TO255OCTETS 0x0390
+#define TITAN_GE_MSTATX_TXFRAMES256TO511OCTETS 0x03A0
+#define TITAN_GE_MSTATX_TXFRAMES512TO1023OCTETS 0x03B0
+#define TITAN_GE_MSTATX_TXFRAMES1024TO1518OCTETS 0x03C0
+#define TITAN_GE_MSTATX_TXFRAMES1519TOMAXSIZE 0x03D0
+#define TITAN_GE_MSTATX_TXVARIABLE 0x03E0
+#define TITAN_GE_MSTATX_RXSYSTEMERROR 0x03F0
+#define TITAN_GE_MSTATX_SINGLECOLLISION 0x0400
+#define TITAN_GE_MSTATX_MULTIPLECOLLISION 0x0410
+#define TITAN_GE_MSTATX_DEFERREDXMISSIONS 0x0420
+#define TITAN_GE_MSTATX_LATECOLLISIONS 0x0430
+#define TITAN_GE_MSTATX_ABORTEDDUETOXSCOLLS 0x0440
+
+/* Interrupt specific defines */
+#define TITAN_GE_DEVICE_ID 0x0000 /* Device ID */
+#define TITAN_GE_RESET 0x0004 /* Reset reg */
+#define TITAN_GE_TSB_CTRL_0 0x000C /* TSB Control reg 0 */
+#define TITAN_GE_TSB_CTRL_1 0x0010 /* TSB Control reg 1 */
+#define TITAN_GE_INTR_GRP0_STATUS 0x0040 /* General Interrupt Group 0 Status */
+#define TITAN_GE_INTR_XDMA_CORE_A 0x0048 /* XDMA Channel Interrupt Status, Core A*/
+#define TITAN_GE_INTR_XDMA_CORE_B 0x004C /* XDMA Channel Interrupt Status, Core B*/
+#define TITAN_GE_INTR_XDMA_IE 0x0058 /* XDMA Channel Interrupt Enable */
+#define TITAN_GE_SDQPF_ECC_INTR 0x480C /* SDQPF ECC Interrupt Status */
+#define TITAN_GE_SDQPF_RXFIFO_CTL 0x4828 /* SDQPF RxFifo Control and Interrupt Enb*/
+#define TITAN_GE_SDQPF_RXFIFO_INTR 0x482C /* SDQPF RxFifo Interrupt Status */
+#define TITAN_GE_SDQPF_TXFIFO_CTL 0x4928 /* SDQPF TxFifo Control and Interrupt Enb*/
+#define TITAN_GE_SDQPF_TXFIFO_INTR 0x492C /* SDQPF TxFifo Interrupt Status */
+#define TITAN_GE_SDQPF_RXFIFO_0 0x4840 /* SDQPF RxFIFO Enable */
+#define TITAN_GE_SDQPF_TXFIFO_0 0x4940 /* SDQPF TxFIFO Enable */
+#define TITAN_GE_XDMA_CONFIG 0x5000 /* XDMA Global Configuration */
+#define TITAN_GE_XDMA_INTR_SUMMARY 0x5010 /* XDMA Interrupt Summary */
+#define TITAN_GE_XDMA_BUFADDRPRE 0x5018 /* XDMA Buffer Address Prefix */
+#define TITAN_GE_XDMA_DESCADDRPRE 0x501C /* XDMA Descriptor Address Prefix */
+#define TITAN_GE_XDMA_PORTWEIGHT 0x502C /* XDMA Port Weight Configuration */
+
+/* Rx MAC defines */
+#define TITAN_GE_RMAC_CONFIG_1 0x1200 /* RMAC Configuration 1 */
+#define TITAN_GE_RMAC_CONFIG_2 0x1204 /* RMAC Configuration 2 */
+#define TITAN_GE_RMAC_MAX_FRAME_LEN 0x1208 /* RMAC Max Frame Length */
+#define TITAN_GE_RMAC_STATION_HI 0x120C /* Rx Station Address High */
+#define TITAN_GE_RMAC_STATION_MID 0x1210 /* Rx Station Address Middle */
+#define TITAN_GE_RMAC_STATION_LOW 0x1214 /* Rx Station Address Low */
+#define TITAN_GE_RMAC_LINK_CONFIG 0x1218 /* RMAC Link Configuration */
+
+/* Tx MAC defines */
+#define TITAN_GE_TMAC_CONFIG_1 0x1240 /* TMAC Configuration 1 */
+#define TITAN_GE_TMAC_CONFIG_2 0x1244 /* TMAC Configuration 2 */
+#define TITAN_GE_TMAC_IPG 0x1248 /* TMAC Inter-Packet Gap */
+#define TITAN_GE_TMAC_STATION_HI 0x124C /* Tx Station Address High */
+#define TITAN_GE_TMAC_STATION_MID 0x1250 /* Tx Station Address Middle */
+#define TITAN_GE_TMAC_STATION_LOW 0x1254 /* Tx Station Address Low */
+#define TITAN_GE_TMAC_MAX_FRAME_LEN 0x1258 /* TMAC Max Frame Length */
+#define TITAN_GE_TMAC_MIN_FRAME_LEN 0x125C /* TMAC Min Frame Length */
+#define TITAN_GE_TMAC_PAUSE_FRAME_TIME 0x1260 /* TMAC Pause Frame Time */
+#define TITAN_GE_TMAC_PAUSE_FRAME_INTERVAL 0x1264 /* TMAC Pause Frame Interval */
+
+/* GMII register */
+#define TITAN_GE_GMII_INTERRUPT_STATUS 0x1348 /* GMII Interrupt Status */
+#define TITAN_GE_GMII_CONFIG_GENERAL 0x134C /* GMII Configuration General */
+#define TITAN_GE_GMII_CONFIG_MODE 0x1350 /* GMII Configuration Mode */
+
+/* Tx and Rx XDMA defines */
+#define TITAN_GE_INT_COALESCING 0x5030 /* Interrupt Coalescing */
+#define TITAN_GE_CHANNEL0_CONFIG 0x5040 /* Channel 0 XDMA config */
+#define TITAN_GE_CHANNEL0_INTERRUPT 0x504c /* Channel 0 Interrupt Status */
+#define TITAN_GE_GDI_INTERRUPT_ENABLE 0x5050 /* IE for the GDI Errors */
+#define TITAN_GE_CHANNEL0_PACKET 0x5060 /* Channel 0 Packet count */
+#define TITAN_GE_CHANNEL0_BYTE 0x5064 /* Channel 0 Byte count */
+#define TITAN_GE_CHANNEL0_TX_DESC 0x5054 /* Channel 0 Tx first desc */
+#define TITAN_GE_CHANNEL0_RX_DESC 0x5058 /* Channel 0 Rx first desc */
+
+/* AFX (Address Filter Exact) register offsets for Slice 0 */
+#define TITAN_GE_AFX_EXACT_MATCH_LOW 0x1100 /* AFX Exact Match Address Low*/
+#define TITAN_GE_AFX_EXACT_MATCH_MID 0x1104 /* AFX Exact Match Address Mid*/
+#define TITAN_GE_AFX_EXACT_MATCH_HIGH 0x1108 /* AFX Exact Match Address Hi */
+#define TITAN_GE_AFX_EXACT_MATCH_VID 0x110C /* AFX Exact Match VID */
+#define TITAN_GE_AFX_MULTICAST_HASH_LOW 0x1110 /* AFX Multicast HASH Low */
+#define TITAN_GE_AFX_MULTICAST_HASH_MIDLOW 0x1114 /* AFX Multicast HASH MidLow */
+#define TITAN_GE_AFX_MULTICAST_HASH_MIDHI 0x1118 /* AFX Multicast HASH MidHi */
+#define TITAN_GE_AFX_MULTICAST_HASH_HI 0x111C /* AFX Multicast HASH Hi */
+#define TITAN_GE_AFX_ADDRS_FILTER_CTRL_0 0x1120 /* AFX Address Filter Ctrl 0 */
+#define TITAN_GE_AFX_ADDRS_FILTER_CTRL_1 0x1124 /* AFX Address Filter Ctrl 1 */
+#define TITAN_GE_AFX_ADDRS_FILTER_CTRL_2 0x1128 /* AFX Address Filter Ctrl 2 */
+
+/* Traffic Groomer block */
+#define TITAN_GE_TRTG_CONFIG 0x1000 /* TRTG Config */
+
+#endif /* _TITAN_GE_H_ */
+
diff --git a/drivers/net/titan_mdio.c b/drivers/net/titan_mdio.c
new file mode 100644
index 0000000..8a8785b
--- /dev/null
+++ b/drivers/net/titan_mdio.c
@@ -0,0 +1,217 @@
+/*
+ * drivers/net/titan_mdio.c - Driver for Titan ethernet ports
+ *
+ * Copyright (C) 2003 PMC-Sierra Inc.
+ * Author : Manish Lachwani (lachwani@pmc-sierra.com)
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * Management Data IO (MDIO) driver for the Titan GMII. Interacts with the Marvel PHY
+ * on the Titan. No support for the TBI as yet.
+ *
+ */
+
+#include "titan_mdio.h"
+
+#define MDIO_DEBUG
+
+/*
+ * Local constants
+ */
+#define MAX_CLKA 1023
+#define MAX_PHY_DEV 31
+#define MAX_PHY_REG 31
+#define WRITEADDRS_OPCODE 0x0
+#define READ_OPCODE 0x2
+#define WRITE_OPCODE 0x1
+#define MAX_MDIO_POLL 100
+
+/*
+ * Titan MDIO and SCMB registers
+ */
+#define TITAN_GE_SCMB_CONTROL 0x01c0 /* SCMB Control */
+#define TITAN_GE_SCMB_CLKA 0x01c4 /* SCMB Clock A */
+#define TITAN_GE_MDIO_COMMAND 0x01d0 /* MDIO Command */
+#define TITAN_GE_MDIO_DEVICE_PORT_ADDRESS 0x01d4 /* MDIO Device and Port addrs */
+#define TITAN_GE_MDIO_DATA 0x01d8 /* MDIO Data */
+#define TITAN_GE_MDIO_INTERRUPTS 0x01dC /* MDIO Interrupts */
+
+/*
+ * Function to poll the MDIO
+ */
+static int titan_ge_mdio_poll(void)
+{
+ int i, val;
+
+ for (i = 0; i < MAX_MDIO_POLL; i++) {
+ val = TITAN_GE_MDIO_READ(TITAN_GE_MDIO_COMMAND);
+
+ if (!(val & 0x8000))
+ return TITAN_GE_MDIO_GOOD;
+ }
+
+ return TITAN_GE_MDIO_ERROR;
+}
+
+
+/*
+ * Initialize and configure the MDIO
+ */
+int titan_ge_mdio_setup(titan_ge_mdio_config *titan_mdio)
+{
+ unsigned long val;
+
+ /* Reset the SCMB and program into MDIO mode*/
+ TITAN_GE_MDIO_WRITE(TITAN_GE_SCMB_CONTROL, 0x9000);
+ TITAN_GE_MDIO_WRITE(TITAN_GE_SCMB_CONTROL, 0x1000);
+
+ /* CLK A */
+ val = TITAN_GE_MDIO_READ(TITAN_GE_SCMB_CLKA);
+ val = ( (val & ~(0x03ff)) | (titan_mdio->clka & 0x03ff));
+ TITAN_GE_MDIO_WRITE(TITAN_GE_SCMB_CLKA, val);
+
+ /* Preamble Suppresion */
+ val = TITAN_GE_MDIO_READ(TITAN_GE_MDIO_COMMAND);
+ val = ( (val & ~(0x0001)) | (titan_mdio->mdio_spre & 0x0001));
+ TITAN_GE_MDIO_WRITE(TITAN_GE_MDIO_COMMAND, val);
+
+ /* MDIO mode */
+ val = TITAN_GE_MDIO_READ(TITAN_GE_MDIO_DEVICE_PORT_ADDRESS);
+ val = ( (val & ~(0x4000)) | (titan_mdio->mdio_mode & 0x4000));
+ TITAN_GE_MDIO_WRITE(TITAN_GE_MDIO_DEVICE_PORT_ADDRESS, val);
+
+ return TITAN_GE_MDIO_GOOD;
+}
+
+/*
+ * Set the PHY address in indirect mode
+ */
+int titan_ge_mdio_inaddrs(int dev_addr, int reg_addr)
+{
+ volatile unsigned long val;
+
+ /* Setup the PHY device */
+ val = TITAN_GE_MDIO_READ(TITAN_GE_MDIO_DEVICE_PORT_ADDRESS);
+ val = ( (val & ~(0x1f00)) | ( (dev_addr << 8) & 0x1f00));
+ val = ( (val & ~(0x001f)) | ( reg_addr & 0x001f));
+ TITAN_GE_MDIO_WRITE(TITAN_GE_MDIO_DEVICE_PORT_ADDRESS, val);
+
+ /* Write the new address */
+ val = TITAN_GE_MDIO_READ(TITAN_GE_MDIO_COMMAND);
+ val = ( (val & ~(0x0300)) | ( (WRITEADDRS_OPCODE << 8) & 0x0300));
+ TITAN_GE_MDIO_WRITE(TITAN_GE_MDIO_COMMAND, val);
+
+ return TITAN_GE_MDIO_GOOD;
+}
+
+/*
+ * Read the MDIO register. This is what the individual parametes mean:
+ *
+ * dev_addr : PHY ID
+ * reg_addr : register offset
+ *
+ * See the spec for the Titan MAC. We operate in the Direct Mode.
+ */
+
+#define MAX_RETRIES 2
+
+int titan_ge_mdio_read(int dev_addr, int reg_addr, unsigned int *pdata)
+{
+ volatile unsigned long val;
+ int retries = 0;
+
+ /* Setup the PHY device */
+
+again:
+ val = TITAN_GE_MDIO_READ(TITAN_GE_MDIO_DEVICE_PORT_ADDRESS);
+ val = ( (val & ~(0x1f00)) | ( (dev_addr << 8) & 0x1f00));
+ val = ( (val & ~(0x001f)) | ( reg_addr & 0x001f));
+ val |= 0x4000;
+ TITAN_GE_MDIO_WRITE(TITAN_GE_MDIO_DEVICE_PORT_ADDRESS, val);
+
+ udelay(30);
+
+ /* Issue the read command */
+ val = TITAN_GE_MDIO_READ(TITAN_GE_MDIO_COMMAND);
+ val = ( (val & ~(0x0300)) | ( (READ_OPCODE << 8) & 0x0300));
+ TITAN_GE_MDIO_WRITE(TITAN_GE_MDIO_COMMAND, val);
+
+ udelay(30);
+
+ if (titan_ge_mdio_poll() != TITAN_GE_MDIO_GOOD)
+ return TITAN_GE_MDIO_ERROR;
+
+ *pdata = (unsigned int)TITAN_GE_MDIO_READ(TITAN_GE_MDIO_DATA);
+ val = TITAN_GE_MDIO_READ(TITAN_GE_MDIO_INTERRUPTS);
+
+ udelay(30);
+
+ if (val & 0x2) {
+ if (retries == MAX_RETRIES)
+ return TITAN_GE_MDIO_ERROR;
+ else {
+ retries++;
+ goto again;
+ }
+ }
+
+ return TITAN_GE_MDIO_GOOD;
+}
+
+/*
+ * Write to the MDIO register
+ *
+ * dev_addr : PHY ID
+ * reg_addr : register that needs to be written to
+ *
+ */
+int titan_ge_mdio_write(int dev_addr, int reg_addr, unsigned int data)
+{
+ volatile unsigned long val;
+
+ if (titan_ge_mdio_poll() != TITAN_GE_MDIO_GOOD)
+ return TITAN_GE_MDIO_ERROR;
+
+ /* Setup the PHY device */
+ val = TITAN_GE_MDIO_READ(TITAN_GE_MDIO_DEVICE_PORT_ADDRESS);
+ val = ( (val & ~(0x1f00)) | ( (dev_addr << 8) & 0x1f00));
+ val = ( (val & ~(0x001f)) | ( reg_addr & 0x001f));
+ val |= 0x4000;
+ TITAN_GE_MDIO_WRITE(TITAN_GE_MDIO_DEVICE_PORT_ADDRESS, val);
+
+ udelay(30);
+
+ /* Setup the data to write */
+ TITAN_GE_MDIO_WRITE(TITAN_GE_MDIO_DATA, data);
+
+ udelay(30);
+
+ /* Issue the write command */
+ val = TITAN_GE_MDIO_READ(TITAN_GE_MDIO_COMMAND);
+ val = ( (val & ~(0x0300)) | ( (WRITE_OPCODE << 8) & 0x0300));
+ TITAN_GE_MDIO_WRITE(TITAN_GE_MDIO_COMMAND, val);
+
+ udelay(30);
+
+ if (titan_ge_mdio_poll() != TITAN_GE_MDIO_GOOD)
+ return TITAN_GE_MDIO_ERROR;
+
+ val = TITAN_GE_MDIO_READ(TITAN_GE_MDIO_INTERRUPTS);
+ if (val & 0x2)
+ return TITAN_GE_MDIO_ERROR;
+
+ return TITAN_GE_MDIO_GOOD;
+}
+
diff --git a/drivers/net/titan_mdio.h b/drivers/net/titan_mdio.h
new file mode 100644
index 0000000..5d23344
--- /dev/null
+++ b/drivers/net/titan_mdio.h
@@ -0,0 +1,56 @@
+/*
+ * MDIO used to interact with the PHY when using GMII/MII
+ */
+#ifndef _TITAN_MDIO_H
+#define _TITAN_MDIO_H
+
+#include <linux/netdevice.h>
+#include <linux/workqueue.h>
+#include <linux/delay.h>
+#include "titan_ge.h"
+
+
+#define TITAN_GE_MDIO_ERROR (-9000)
+#define TITAN_GE_MDIO_GOOD 0
+
+#define TITAN_GE_MDIO_BASE titan_ge_base
+
+#define TITAN_GE_MDIO_READ(offset) \
+ *(volatile u32 *)(titan_ge_base + (offset))
+
+#define TITAN_GE_MDIO_WRITE(offset, data) \
+ *(volatile u32 *)(titan_ge_base + (offset)) = (data)
+
+
+/* GMII specific registers */
+#define TITAN_GE_MARVEL_PHY_ID 0x00
+#define TITAN_PHY_AUTONEG_ADV 0x04
+#define TITAN_PHY_LP_ABILITY 0x05
+#define TITAN_GE_MDIO_MII_CTRL 0x09
+#define TITAN_GE_MDIO_MII_EXTENDED 0x0f
+#define TITAN_GE_MDIO_PHY_CTRL 0x10
+#define TITAN_GE_MDIO_PHY_STATUS 0x11
+#define TITAN_GE_MDIO_PHY_IE 0x12
+#define TITAN_GE_MDIO_PHY_IS 0x13
+#define TITAN_GE_MDIO_PHY_LED 0x18
+#define TITAN_GE_MDIO_PHY_LED_OVER 0x19
+#define PHY_ANEG_TIME_WAIT 45 /* 45 seconds wait time */
+
+/*
+ * MDIO Config Structure
+ */
+typedef struct {
+ unsigned int clka;
+ int mdio_spre;
+ int mdio_mode;
+} titan_ge_mdio_config;
+
+/*
+ * Function Prototypes
+ */
+int titan_ge_mdio_setup(titan_ge_mdio_config *);
+int titan_ge_mdio_inaddrs(int, int);
+int titan_ge_mdio_read(int, int, unsigned int *);
+int titan_ge_mdio_write(int, int, unsigned int);
+
+#endif /* _TITAN_MDIO_H */
diff --git a/drivers/net/wireless/Kconfig b/drivers/net/wireless/Kconfig
index f354bd4..eab6234 100644
--- a/drivers/net/wireless/Kconfig
+++ b/drivers/net/wireless/Kconfig
@@ -217,8 +217,106 @@
If you choose to build a module, it'll be called rndis_wlan.
+config RTL8180
+ tristate "Realtek 8180/8185 PCI support"
+ depends on MAC80211 && PCI && EXPERIMENTAL
+ select EEPROM_93CX6
+ ---help---
+ This is a driver for RTL8180 and RTL8185 based cards.
+ These are PCI based chips found in cards such as:
+
+ (RTL8185 802.11g)
+ A-Link WL54PC
+
+ (RTL8180 802.11b)
+ Belkin F5D6020 v3
+ Belkin F5D6020 v3
+ Dlink DWL-610
+ Dlink DWL-510
+ Netgear MA521
+ Level-One WPC-0101
+ Acer Aspire 1357 LMi
+ VCTnet PC-11B1
+ Ovislink AirLive WL-1120PCM
+ Mentor WL-PCI
+ Linksys WPC11 v4
+ TrendNET TEW-288PI
+ D-Link DWL-520 Rev D
+ Repotec RP-WP7126
+ TP-Link TL-WN250/251
+ Zonet ZEW1000
+ Longshine LCS-8031-R
+ HomeLine HLW-PCC200
+ GigaFast WF721-AEX
+ Planet WL-3553
+ Encore ENLWI-PCI1-NT
+ TrendNET TEW-266PC
+ Gigabyte GN-WLMR101
+ Siemens-fujitsu Amilo D1840W
+ Edimax EW-7126
+ PheeNet WL-11PCIR
+ Tonze PC-2100T
+ Planet WL-8303
+ Dlink DWL-650 v M1
+ Edimax EW-7106
+ Q-Tec 770WC
+ Topcom Skyr@cer 4011b
+ Roper FreeLan 802.11b (edition 2004)
+ Wistron Neweb Corp CB-200B
+ Pentagram HorNET
+ QTec 775WC
+ TwinMOS Booming B Series
+ Micronet SP906BB
+ Sweex LC700010
+ Surecom EP-9428
+ Safecom SWLCR-1100
+
+ Thanks to Realtek for their support!
+
+config RTL8187
+ tristate "Realtek 8187 and 8187B USB support"
+ depends on MAC80211 && USB && !LEMOTE_MACH2F
+ select EEPROM_93CX6
+ ---help---
+ This is a driver for RTL8187 and RTL8187B based cards.
+ These are USB based chips found in devices such as:
+
+ Netgear WG111v2
+ Level 1 WNC-0301USB
+ Micronet SP907GK V5
+ Encore ENUWI-G2
+ Trendnet TEW-424UB
+ ASUS P5B Deluxe/P5K Premium motherboards
+ Toshiba Satellite Pro series of laptops
+ Asus Wireless Link
+ Linksys WUSB54GC-EU v2
+ (v1 = rt73usb; v3 is rt2070-based,
+ use staging/rt3070 or try rt2800usb)
+
+ Thanks to Realtek for their support!
+
+# If possible, automatically enable LEDs for RTL8187.
+
+config RTL8187_LEDS
+ bool
+ depends on RTL8187 && MAC80211_LEDS && (LEDS_CLASS = y || LEDS_CLASS = RTL8187)
+ default y
+
source "drivers/net/wireless/rtl818x/Kconfig"
+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 --git a/drivers/net/wireless/Makefile b/drivers/net/wireless/Makefile
index 7bba6a8..7ef4ecf 100644
--- a/drivers/net/wireless/Makefile
+++ b/drivers/net/wireless/Makefile
@@ -24,7 +24,8 @@
obj-$(CONFIG_ZD1211RW) += zd1211rw/
obj-$(CONFIG_RTL8180) += rtl818x/
obj-$(CONFIG_RTL8187) += rtl818x/
-obj-$(CONFIG_RTLWIFI) += rtlwifi/
+obj-$(CONFIG_RTL8187B) += rtl8187b/
+obj-$(CONFIG_RTL8192CE) += rtlwifi/
# 16-bit wireless PCMCIA client drivers
obj-$(CONFIG_PCMCIA_RAYCS) += ray_cs.o
diff --git a/drivers/net/wireless/rtl8187b/Makefile b/drivers/net/wireless/rtl8187b/Makefile
new file mode 100644
index 0000000..c688cc9
--- /dev/null
+++ b/drivers/net/wireless/rtl8187b/Makefile
@@ -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 --git a/drivers/net/wireless/rtl8187b/dot11d.h b/drivers/net/wireless/rtl8187b/dot11d.h
new file mode 100644
index 0000000..99010be
--- /dev/null
+++ b/drivers/net/wireless/rtl8187b/dot11d.h
@@ -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 --git a/drivers/net/wireless/rtl8187b/ieee80211/arc4.c b/drivers/net/wireless/rtl8187b/ieee80211/arc4.c
new file mode 100644
index 0000000..e93e5e2
--- /dev/null
+++ b/drivers/net/wireless/rtl8187b/ieee80211/arc4.c
@@ -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 --git a/drivers/net/wireless/rtl8187b/ieee80211/dot11d.c b/drivers/net/wireless/rtl8187b/ieee80211/dot11d.c
new file mode 100644
index 0000000..8d662b5
--- /dev/null
+++ b/drivers/net/wireless/rtl8187b/ieee80211/dot11d.c
@@ -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 --git a/drivers/net/wireless/rtl8187b/ieee80211/dot11d.h b/drivers/net/wireless/rtl8187b/ieee80211/dot11d.h
new file mode 100644
index 0000000..64bcf15
--- /dev/null
+++ b/drivers/net/wireless/rtl8187b/ieee80211/dot11d.h
@@ -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 --git a/drivers/net/wireless/rtl8187b/ieee80211/ieee80211.h b/drivers/net/wireless/rtl8187b/ieee80211/ieee80211.h
new file mode 100644
index 0000000..e9ea893
--- /dev/null
+++ b/drivers/net/wireless/rtl8187b/ieee80211/ieee80211.h
@@ -0,0 +1,1904 @@
+/*
+ * 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>
+#include <linux/semaphore.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 --git a/drivers/net/wireless/rtl8187b/ieee80211/ieee80211_crypt.c b/drivers/net/wireless/rtl8187b/ieee80211/ieee80211_crypt.c
new file mode 100644
index 0000000..57a6696
--- /dev/null
+++ b/drivers/net/wireless/rtl8187b/ieee80211/ieee80211_crypt.c
@@ -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 --git a/drivers/net/wireless/rtl8187b/ieee80211/ieee80211_crypt.h b/drivers/net/wireless/rtl8187b/ieee80211/ieee80211_crypt.h
new file mode 100644
index 0000000..5fa8764
--- /dev/null
+++ b/drivers/net/wireless/rtl8187b/ieee80211/ieee80211_crypt.h
@@ -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 --git a/drivers/net/wireless/rtl8187b/ieee80211/ieee80211_crypt_ccmp.c b/drivers/net/wireless/rtl8187b/ieee80211/ieee80211_crypt_ccmp.c
new file mode 100644
index 0000000..37f4259
--- /dev/null
+++ b/drivers/net/wireless/rtl8187b/ieee80211/ieee80211_crypt_ccmp.c
@@ -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 --git a/drivers/net/wireless/rtl8187b/ieee80211/ieee80211_crypt_tkip.c b/drivers/net/wireless/rtl8187b/ieee80211/ieee80211_crypt_tkip.c
new file mode 100644
index 0000000..92a6e93
--- /dev/null
+++ b/drivers/net/wireless/rtl8187b/ieee80211/ieee80211_crypt_tkip.c
@@ -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 --git a/drivers/net/wireless/rtl8187b/ieee80211/ieee80211_crypt_wep.c b/drivers/net/wireless/rtl8187b/ieee80211/ieee80211_crypt_wep.c
new file mode 100644
index 0000000..d97b637
--- /dev/null
+++ b/drivers/net/wireless/rtl8187b/ieee80211/ieee80211_crypt_wep.c
@@ -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 --git a/drivers/net/wireless/rtl8187b/ieee80211/ieee80211_module.c b/drivers/net/wireless/rtl8187b/ieee80211/ieee80211_module.c
new file mode 100644
index 0000000..b85f6dd
--- /dev/null
+++ b/drivers/net/wireless/rtl8187b/ieee80211/ieee80211_module.c
@@ -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 --git a/drivers/net/wireless/rtl8187b/ieee80211/ieee80211_rx.c b/drivers/net/wireless/rtl8187b/ieee80211/ieee80211_rx.c
new file mode 100644
index 0000000..769203c
--- /dev/null
+++ b/drivers/net/wireless/rtl8187b/ieee80211/ieee80211_rx.c
@@ -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 --git a/drivers/net/wireless/rtl8187b/ieee80211/ieee80211_softmac.c b/drivers/net/wireless/rtl8187b/ieee80211/ieee80211_softmac.c
new file mode 100644
index 0000000..c4b8629
--- /dev/null
+++ b/drivers/net/wireless/rtl8187b/ieee80211/ieee80211_softmac.c
@@ -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 --git a/drivers/net/wireless/rtl8187b/ieee80211/ieee80211_softmac_wx.c b/drivers/net/wireless/rtl8187b/ieee80211/ieee80211_softmac_wx.c
new file mode 100644
index 0000000..a23b9d0
--- /dev/null
+++ b/drivers/net/wireless/rtl8187b/ieee80211/ieee80211_softmac_wx.c
@@ -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 --git a/drivers/net/wireless/rtl8187b/ieee80211/ieee80211_tx.c b/drivers/net/wireless/rtl8187b/ieee80211/ieee80211_tx.c
new file mode 100644
index 0000000..cad850f
--- /dev/null
+++ b/drivers/net/wireless/rtl8187b/ieee80211/ieee80211_tx.c
@@ -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 --git a/drivers/net/wireless/rtl8187b/ieee80211/ieee80211_wx.c b/drivers/net/wireless/rtl8187b/ieee80211/ieee80211_wx.c
new file mode 100644
index 0000000..a5dffeb
--- /dev/null
+++ b/drivers/net/wireless/rtl8187b/ieee80211/ieee80211_wx.c
@@ -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) * 100 / HZ );
+ 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 --git a/drivers/net/wireless/rtl8187b/ieee80211/internal.h b/drivers/net/wireless/rtl8187b/ieee80211/internal.h
new file mode 100644
index 0000000..189f285
--- /dev/null
+++ b/drivers/net/wireless/rtl8187b/ieee80211/internal.h
@@ -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 --git a/drivers/net/wireless/rtl8187b/ieee80211/kmap_types.h b/drivers/net/wireless/rtl8187b/ieee80211/kmap_types.h
new file mode 100644
index 0000000..de67bb0
--- /dev/null
+++ b/drivers/net/wireless/rtl8187b/ieee80211/kmap_types.h
@@ -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 --git a/drivers/net/wireless/rtl8187b/ieee80211/readme b/drivers/net/wireless/rtl8187b/ieee80211/readme
new file mode 100644
index 0000000..bc04ffb
--- /dev/null
+++ b/drivers/net/wireless/rtl8187b/ieee80211/readme
@@ -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 --git a/drivers/net/wireless/rtl8187b/ieee80211/rtl8187_mesh.h b/drivers/net/wireless/rtl8187b/ieee80211/rtl8187_mesh.h
new file mode 100644
index 0000000..80f23ea
--- /dev/null
+++ b/drivers/net/wireless/rtl8187b/ieee80211/rtl8187_mesh.h
@@ -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 --git a/drivers/net/wireless/rtl8187b/ieee80211/rtl_crypto.h b/drivers/net/wireless/rtl8187b/ieee80211/rtl_crypto.h
new file mode 100644
index 0000000..82fa2b7
--- /dev/null
+++ b/drivers/net/wireless/rtl8187b/ieee80211/rtl_crypto.h
@@ -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 --git a/drivers/net/wireless/rtl8187b/ieee80211/scatterwalk.h b/drivers/net/wireless/rtl8187b/ieee80211/scatterwalk.h
new file mode 100644
index 0000000..b164465
--- /dev/null
+++ b/drivers/net/wireless/rtl8187b/ieee80211/scatterwalk.h
@@ -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 --git a/drivers/net/wireless/rtl8187b/msh_class.h b/drivers/net/wireless/rtl8187b/msh_class.h
new file mode 100644
index 0000000..ccaa939
--- /dev/null
+++ b/drivers/net/wireless/rtl8187b/msh_class.h
@@ -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 --git a/drivers/net/wireless/rtl8187b/r8180_93cx6.c b/drivers/net/wireless/rtl8187b/r8180_93cx6.c
new file mode 100644
index 0000000..8de9153
--- /dev/null
+++ b/drivers/net/wireless/rtl8187b/r8180_93cx6.c
@@ -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 --git a/drivers/net/wireless/rtl8187b/r8180_93cx6.h b/drivers/net/wireless/rtl8187b/r8180_93cx6.h
new file mode 100644
index 0000000..4d08565
--- /dev/null
+++ b/drivers/net/wireless/rtl8187b/r8180_93cx6.h
@@ -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 --git a/drivers/net/wireless/rtl8187b/r8180_dm.c b/drivers/net/wireless/rtl8187b/r8180_dm.c
new file mode 100644
index 0000000..684610e
--- /dev/null
+++ b/drivers/net/wireless/rtl8187b/r8180_dm.c
@@ -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 --git a/drivers/net/wireless/rtl8187b/r8180_dm.h b/drivers/net/wireless/rtl8187b/r8180_dm.h
new file mode 100644
index 0000000..2b7e671
--- /dev/null
+++ b/drivers/net/wireless/rtl8187b/r8180_dm.h
@@ -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 --git a/drivers/net/wireless/rtl8187b/r8180_hw.h b/drivers/net/wireless/rtl8187b/r8180_hw.h
new file mode 100644
index 0000000..c050fca
--- /dev/null
+++ b/drivers/net/wireless/rtl8187b/r8180_hw.h
@@ -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 --git a/drivers/net/wireless/rtl8187b/r8180_pm.c b/drivers/net/wireless/rtl8187b/r8180_pm.c
new file mode 100644
index 0000000..90a0bd9
--- /dev/null
+++ b/drivers/net/wireless/rtl8187b/r8180_pm.c
@@ -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 --git a/drivers/net/wireless/rtl8187b/r8180_pm.h b/drivers/net/wireless/rtl8187b/r8180_pm.h
new file mode 100644
index 0000000..efcba1d
--- /dev/null
+++ b/drivers/net/wireless/rtl8187b/r8180_pm.h
@@ -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 --git a/drivers/net/wireless/rtl8187b/r8180_rtl8225.c b/drivers/net/wireless/rtl8187b/r8180_rtl8225.c
new file mode 100644
index 0000000..e53d4cd
--- /dev/null
+++ b/drivers/net/wireless/rtl8187b/r8180_rtl8225.c
@@ -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 --git a/drivers/net/wireless/rtl8187b/r8180_rtl8225.h b/drivers/net/wireless/rtl8187b/r8180_rtl8225.h
new file mode 100644
index 0000000..138e0d0
--- /dev/null
+++ b/drivers/net/wireless/rtl8187b/r8180_rtl8225.h
@@ -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 --git a/drivers/net/wireless/rtl8187b/r8180_rtl8225z2.c b/drivers/net/wireless/rtl8187b/r8180_rtl8225z2.c
new file mode 100644
index 0000000..b661ab5
--- /dev/null
+++ b/drivers/net/wireless/rtl8187b/r8180_rtl8225z2.c
@@ -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 --git a/drivers/net/wireless/rtl8187b/r8180_wx.c b/drivers/net/wireless/rtl8187b/r8180_wx.c
new file mode 100644
index 0000000..2bb9fe3
--- /dev/null
+++ b/drivers/net/wireless/rtl8187b/r8180_wx.c
@@ -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 --git a/drivers/net/wireless/rtl8187b/r8180_wx.h b/drivers/net/wireless/rtl8187b/r8180_wx.h
new file mode 100644
index 0000000..0c62a99
--- /dev/null
+++ b/drivers/net/wireless/rtl8187b/r8180_wx.h
@@ -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 --git a/drivers/net/wireless/rtl8187b/r8187.h b/drivers/net/wireless/rtl8187b/r8187.h
new file mode 100644
index 0000000..ab18683
--- /dev/null
+++ b/drivers/net/wireless/rtl8187b/r8187.h
@@ -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 --git a/drivers/net/wireless/rtl8187b/r8187_core.c b/drivers/net/wireless/rtl8187b/r8187_core.c
new file mode 100644
index 0000000..e3ce75b
--- /dev/null
+++ b/drivers/net/wireless/rtl8187b/r8187_core.c
@@ -0,0 +1,7047 @@
+/*
+ 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 */
+ .reset_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 CONFIG_PM
+ udev->reset_resume = 1;
+#endif
+
+#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);
+ register_netdev(dev);
+ netif_stop_queue(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 --git a/drivers/net/wireless/rtl8187b/r8187_led.c b/drivers/net/wireless/rtl8187b/r8187_led.c
new file mode 100644
index 0000000..dba3b5a
--- /dev/null
+++ b/drivers/net/wireless/rtl8187b/r8187_led.c
@@ -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 --git a/drivers/net/wireless/rtl8187b/r8187_led.h b/drivers/net/wireless/rtl8187b/r8187_led.h
new file mode 100644
index 0000000..83492db
--- /dev/null
+++ b/drivers/net/wireless/rtl8187b/r8187_led.h
@@ -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 --git a/drivers/net/wireless/rtl8187b/r8187_rfkill.c b/drivers/net/wireless/rtl8187b/r8187_rfkill.c
new file mode 100644
index 0000000..c63877a
--- /dev/null
+++ b/drivers/net/wireless/rtl8187b/r8187_rfkill.c
@@ -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 --git a/drivers/net/wireless/rtl8187b/readme b/drivers/net/wireless/rtl8187b/readme
new file mode 100644
index 0000000..4438d2a
--- /dev/null
+++ b/drivers/net/wireless/rtl8187b/readme
@@ -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 --git a/drivers/net/wireless/rtl818x/rtl8187/dev.c b/drivers/net/wireless/rtl818x/rtl8187/dev.c
index 1e0be14..b6f6f52 100644
--- a/drivers/net/wireless/rtl818x/rtl8187/dev.c
+++ b/drivers/net/wireless/rtl818x/rtl8187/dev.c
@@ -1005,6 +1005,9 @@
u32 reg;
mutex_lock(&priv->conf_mutex);
+
+ priv->vif = NULL;
+
rtl818x_iowrite16(priv, &priv->map->INT_MASK, 0);
reg = rtl818x_ioread8(priv, &priv->map->CMD);
@@ -1065,10 +1068,7 @@
static void rtl8187_remove_interface(struct ieee80211_hw *dev,
struct ieee80211_vif *vif)
{
- struct rtl8187_priv *priv = dev->priv;
- mutex_lock(&priv->conf_mutex);
- priv->vif = NULL;
- mutex_unlock(&priv->conf_mutex);
+ /* Nothing to do */
}
static int rtl8187_config(struct ieee80211_hw *dev, u32 changed)
diff --git a/drivers/net/wireless/rtl818x/rtl8187/rfkill.c b/drivers/net/wireless/rtl818x/rtl8187/rfkill.c
index 3411671..4d252c1 100644
--- a/drivers/net/wireless/rtl818x/rtl8187/rfkill.c
+++ b/drivers/net/wireless/rtl818x/rtl8187/rfkill.c
@@ -22,6 +22,10 @@
static bool rtl8187_is_radio_enabled(struct rtl8187_priv *priv)
{
+#ifdef CONFIG_LEMOTE_MACH2F
+ /* Allow users to activate rfkill through only the /sys interface */
+ return 1;
+#else
u8 gpio;
gpio = rtl818x_ioread8(priv, &priv->map->GPIO0);
@@ -29,6 +33,7 @@
gpio = rtl818x_ioread8(priv, &priv->map->GPIO1);
return gpio & priv->rfkill_mask;
+#endif
}
void rtl8187_rfkill_init(struct ieee80211_hw *hw)
diff --git a/drivers/platform/Kconfig b/drivers/platform/Kconfig
index 8390dca..4fa78d5 100644
--- a/drivers/platform/Kconfig
+++ b/drivers/platform/Kconfig
@@ -1,3 +1,7 @@
if X86
source "drivers/platform/x86/Kconfig"
endif
+
+if MIPS
+source "drivers/platform/mips/Kconfig"
+endif
diff --git a/drivers/platform/Makefile b/drivers/platform/Makefile
index 782953a..8bdc97c 100644
--- a/drivers/platform/Makefile
+++ b/drivers/platform/Makefile
@@ -3,3 +3,4 @@
#
obj-$(CONFIG_X86) += x86/
+obj-$(CONFIG_MIPS) += mips/
diff --git a/drivers/platform/mips/Kconfig b/drivers/platform/mips/Kconfig
new file mode 100644
index 0000000..722d690
--- /dev/null
+++ b/drivers/platform/mips/Kconfig
@@ -0,0 +1,60 @@
+#
+# 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_LCD_SUPPORT
+ select LCD_CLASS_DEVICE
+ select BACKLIGHT_CLASS_DEVICE
+ select POWER_SUPPLY
+ select HWMON
+ select VIDEO_OUTPUT_CONTROL
+ select INPUT_SPARSEKMAP
+ select INPUT_EVDEV
+ depends on INPUT
+ default m
+ 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_LCD_SUPPORT
+ select BACKLIGHT_CLASS_DEVICE
+ select VIDEO_OUTPUT_CONTROL
+ default m
+ 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.
+
+config GDIUM_LAPTOP
+ tristate "GDIUM laptop extras"
+ depends on DEXXON_GDIUM
+ select POWER_SUPPLY
+ select I2C
+ select INPUT_POLLDEV
+ default m
+ help
+ This mini-driver drives the ST7 chipset present in the Gdium laptops.
+ This gives battery support, wlan rfkill.
+
+endif # MIPS_PLATFORM_DEVICES
diff --git a/drivers/platform/mips/Makefile b/drivers/platform/mips/Makefile
new file mode 100644
index 0000000..0eadf8e
--- /dev/null
+++ b/drivers/platform/mips/Makefile
@@ -0,0 +1,8 @@
+#
+# Makefile for MIPS Platform-Specific Drivers
+#
+
+obj-$(CONFIG_LEMOTE_YEELOONG2F) += yeeloong_laptop.o
+
+obj-$(CONFIG_LEMOTE_LYNLOONG2F) += lynloong_pc.o
+obj-$(CONFIG_GDIUM_LAPTOP) += gdium_laptop.o
diff --git a/drivers/platform/mips/gdium_laptop.c b/drivers/platform/mips/gdium_laptop.c
new file mode 100644
index 0000000..41a65ad
--- /dev/null
+++ b/drivers/platform/mips/gdium_laptop.c
@@ -0,0 +1,927 @@
+/*
+ * gdium_laptop -- Gdium laptop extras
+ *
+ * Arnaud Patard <apatard@mandriva.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/init.h>
+#include <linux/platform_device.h>
+#include <linux/input-polldev.h>
+#include <linux/debugfs.h>
+#include <linux/seq_file.h>
+#include <linux/i2c.h>
+#include <linux/mutex.h>
+#include <linux/power_supply.h>
+#include <linux/workqueue.h>
+#include <linux/delay.h>
+#include <linux/slab.h>
+#include <asm/gpio.h>
+
+/* For input device */
+#define SCAN_INTERVAL 150
+
+/* For battery status */
+#define BAT_SCAN_INTERVAL 500
+
+#define EC_FIRM_VERSION 0
+
+#if CONFIG_GDIUM_VERSION > 2
+#define EC_REG_BASE 1
+#else
+#define EC_REG_BASE 0
+#endif
+
+#define EC_STATUS (EC_REG_BASE+0)
+#define EC_STATUS_LID (1<<0)
+#define EC_STATUS_PWRBUT (1<<1)
+#define EC_STATUS_BATID (1<<2) /* this bit has no real meaning on v2. */
+ /* Same as EC_STATUS_ADAPT */
+ /* but on v3 it's BATID which mean bat present */
+#define EC_STATUS_SYS_POWER (1<<3)
+#define EC_STATUS_WLAN (1<<4)
+#define EC_STATUS_ADAPT (1<<5)
+
+#define EC_CTRL (EC_REG_BASE+1)
+#define EC_CTRL_DDR_CLK (1<<0)
+#define EC_CTRL_CHARGE_LED (1<<1)
+#define EC_CTRL_BEEP (1<<2)
+#define EC_CTRL_SUSB (1<<3) /* memory power */
+#define EC_CTRL_TRICKLE (1<<4)
+#define EC_CTRL_WLAN_EN (1<<5)
+#define EC_CTRL_SUSC (1<<6) /* main power */
+#define EC_CTRL_CHARGE_EN (1<<7)
+
+#define EC_BAT_LOW (EC_REG_BASE+2)
+#define EC_BAT_HIGH (EC_REG_BASE+3)
+
+#define EC_SIGN (EC_REG_BASE+4)
+#define EC_SIGN_OS 0xAE /* write 0xae to control pm stuff */
+#define EC_SIGN_EC 0x00 /* write 0x00 to let the st7 manage pm stuff */
+
+#if 0
+#define EC_TEST (EC_REG_BASE+5) /* Depending on firmware version this register */
+ /* may be the programmation register so don't play */
+ /* with it */
+#endif
+
+#define BAT_VOLT_PRESENT 500000 /* Min voltage to consider battery present uV */
+#define BAT_MIN 7000000 /* Min battery voltage in uV */
+#define BAT_MIN_MV 7000 /* Min battery voltage in mV */
+#define BAT_TRICKLE_EN 8000000 /* Charging at 1.4A before 8.0V and then charging at 0.25A */
+#define BAT_MAX 7950000 /* Max battery voltage ~8V in V */
+#define BAT_MAX_MV 7950 /* Max battery voltage ~8V in V */
+#define BAT_READ_ERROR 300000 /* battery read error of 0.3V */
+#define BAT_READ_ERROR_MV 300 /* battery read error of 0.3V */
+
+#define SM502_WLAN_ON (224+16)/* SM502 GPIO16 may be used on gdium v2 (v3?) as wlan_on */
+ /* when R422 is connected */
+
+static unsigned char verbose;
+static unsigned char gpio16;
+static unsigned char ec;
+module_param(verbose, byte, S_IRUGO | S_IWUSR);
+MODULE_PARM_DESC(verbose, "Add some debugging messages");
+module_param(gpio16, byte, S_IRUGO);
+MODULE_PARM_DESC(gpio16, "Enable wlan_on signal on SM502");
+module_param(ec, byte, S_IRUGO);
+MODULE_PARM_DESC(ec, "Let the ST7 handle the battery (default OS)");
+
+struct gdium_laptop_data {
+ struct i2c_client *client;
+ struct input_polled_dev *input_polldev;
+ struct dentry *debugfs;
+ struct mutex mutex;
+ struct platform_device *bat_pdev;
+ struct power_supply gdium_ac;
+ struct power_supply gdium_battery;
+ struct workqueue_struct *workqueue;
+ struct delayed_work work;
+ char charge_cmd;
+ /* important registers value */
+ char status;
+ char ctrl;
+ /* mV */
+ int battery_level;
+ char version;
+};
+
+/**********************************************************************/
+/* Low level I2C functions */
+/* All are supposed to be called with mutex held */
+/**********************************************************************/
+/*
+ * Return battery voltage in mV
+ * >= 0 battery voltage
+ * < 0 error
+ */
+static s32 ec_read_battery(struct i2c_client *client)
+{
+ unsigned char bat_low, bat_high;
+ s32 data;
+ unsigned int ret;
+
+ /*
+ * a = battery high
+ * b = battery low
+ * bat = a << 2 | b & 0x03;
+ * battery voltage = (bat / 1024) * 5 * 2
+ */
+ data = i2c_smbus_read_byte_data(client, EC_BAT_LOW);
+ if (data < 0) {
+ dev_err(&client->dev, "ec_read_bat: read bat_low failed\n");
+ return data;
+ }
+ bat_low = data & 0xff;
+ if (verbose)
+ dev_info(&client->dev, "bat_low %x\n", bat_low);
+
+ data = i2c_smbus_read_byte_data(client, EC_BAT_HIGH);
+ if (data < 0) {
+ dev_err(&client->dev, "ec_read_bat: read bat_high failed\n");
+ return data;
+ }
+ bat_high = data & 0xff;
+ if (verbose)
+ dev_info(&client->dev, "bat_high %x\n", bat_high);
+
+ ret = (bat_high << 2) | (bat_low & 3);
+ /*
+ * mV
+ */
+ ret = (ret * 5 * 2) * 1000 / 1024;
+
+ return ret;
+}
+
+static s32 ec_read_version(struct i2c_client *client)
+{
+#if CONFIG_GDIUM_VERSION > 2
+ return i2c_smbus_read_byte_data(client, EC_FIRM_VERSION);
+#else
+ return 0;
+#endif
+}
+
+static s32 ec_read_status(struct i2c_client *client)
+{
+ return i2c_smbus_read_byte_data(client, EC_STATUS);
+}
+
+static s32 ec_read_ctrl(struct i2c_client *client)
+{
+ return i2c_smbus_read_byte_data(client, EC_CTRL);
+}
+
+static s32 ec_write_ctrl(struct i2c_client *client, unsigned char newvalue)
+{
+ return i2c_smbus_write_byte_data(client, EC_CTRL, newvalue);
+}
+
+static s32 ec_read_sign(struct i2c_client *client)
+{
+ return i2c_smbus_read_byte_data(client, EC_SIGN);
+}
+
+static s32 ec_write_sign(struct i2c_client *client, unsigned char sign)
+{
+ unsigned char value;
+ s32 ret;
+
+ ret = i2c_smbus_write_byte_data(client, EC_SIGN, sign);
+ if (ret < 0) {
+ dev_err(&client->dev, "ec_set_control: write failed\n");
+ return ret;
+ }
+
+ value = ec_read_sign(client);
+ if (value != sign) {
+ dev_err(&client->dev, "Failed to set control to %s\n",
+ sign == EC_SIGN_OS ? "OS" : "EC");
+ return -EIO;
+ }
+
+ return 0;
+}
+
+#if 0
+static int ec_power_off(struct i2c_client *client)
+{
+ char value;
+ int ret;
+
+ value = ec_read_ctrl(client);
+ if (value < 0) {
+ dev_err(&client->dev, "ec_power_off: read failed\n");
+ return value;
+ }
+ value &= ~(EC_CTRL_SUSB | EC_CTRL_SUSC);
+ ret = ec_write_ctrl(client, value);
+ if (ret < 0) {
+ dev_err(&client->dev, "ec_power_off: write failed\n");
+ return ret;
+ }
+
+ return 0;
+}
+#endif
+
+static s32 ec_wlan_status(struct i2c_client *client)
+{
+ s32 value;
+
+ value = ec_read_ctrl(client);
+ if (value < 0)
+ return value;
+
+ return (value & EC_CTRL_WLAN_EN) ? 1 : 0;
+}
+
+static s32 ec_wlan_en(struct i2c_client *client, int on)
+{
+ s32 value;
+
+ value = ec_read_ctrl(client);
+ if (value < 0)
+ return value;
+
+ value &= ~EC_CTRL_WLAN_EN;
+ if (on)
+ value |= EC_CTRL_WLAN_EN;
+
+ return ec_write_ctrl(client, value&0xff);
+}
+
+#if 0
+static s32 ec_led_status(struct i2c_client *client)
+{
+ s32 value;
+
+ value = ec_read_ctrl(client);
+ if (value < 0)
+ return value;
+
+ return (value & EC_CTRL_CHARGE_LED) ? 1 : 0;
+}
+#endif
+
+/* Changing the charging led status has never worked */
+static s32 ec_led_en(struct i2c_client *client, int on)
+{
+#if 0
+ s32 value;
+
+ value = ec_read_ctrl(client);
+ if (value < 0)
+ return value;
+
+ value &= ~EC_CTRL_CHARGE_LED;
+ if (on)
+ value |= EC_CTRL_CHARGE_LED;
+ return ec_write_ctrl(client, value&0xff);
+#else
+ return 0;
+#endif
+}
+
+static s32 ec_charge_en(struct i2c_client *client, int on, int trickle)
+{
+ s32 value;
+ s32 set = 0;
+
+ value = ec_read_ctrl(client);
+ if (value < 0)
+ return value;
+
+ if (on)
+ set |= EC_CTRL_CHARGE_EN;
+ if (trickle)
+ set |= EC_CTRL_TRICKLE;
+
+ /* Be clever : don't change values if you don't need to */
+ if ((value & (EC_CTRL_CHARGE_EN | EC_CTRL_TRICKLE)) == set)
+ return 0;
+
+ value &= ~(EC_CTRL_CHARGE_EN | EC_CTRL_TRICKLE);
+ value |= set;
+ ec_led_en(client, on);
+ return ec_write_ctrl(client, (unsigned char)(value&0xff));
+
+}
+
+/**********************************************************************/
+/* Input functions */
+/**********************************************************************/
+struct gdium_keys {
+ int last_state;
+ int key_code;
+ int mask;
+ int type;
+};
+
+static struct gdium_keys gkeys[] = {
+ {
+ .key_code = KEY_WLAN,
+ .mask = EC_STATUS_WLAN,
+ .type = EV_KEY,
+ },
+ {
+ .key_code = KEY_POWER,
+ .mask = EC_STATUS_PWRBUT,
+ .type = EV_KEY, /*EV_PWR,*/
+ },
+ {
+ .key_code = SW_LID,
+ .mask = EC_STATUS_LID,
+ .type = EV_SW,
+ },
+};
+
+static void gdium_laptop_keys_poll(struct input_polled_dev *dev)
+{
+ int state, i;
+ struct gdium_laptop_data *data = dev->private;
+ struct i2c_client *client = data->client;
+ struct input_dev *input = dev->input;
+ s32 status;
+
+ mutex_lock(&data->mutex);
+ status = ec_read_status(client);
+ mutex_unlock(&data->mutex);
+
+ if (status < 0) {
+ /*
+ * Don't know exactly which version of the firmware
+ * has this bug but when the power button is pressed
+ * there are i2c read errors :(
+ */
+ if ((data->version >= 0x13) && !gkeys[1].last_state) {
+ input_event(input, EV_KEY, KEY_POWER, 1);
+ input_sync(input);
+ gkeys[1].last_state = 1;
+ }
+ return;
+ }
+
+ for (i = 0; i < ARRAY_SIZE(gkeys); i++) {
+ state = status & gkeys[i].mask;
+ if (state != gkeys[i].last_state) {
+ gkeys[i].last_state = state;
+ /* for power key, we want power & key press/release event */
+ if (gkeys[i].type == EV_PWR) {
+ input_event(input, EV_KEY, gkeys[i].key_code, !!state);
+ input_sync(input);
+ }
+ /* Disable wifi on key press but not key release */
+ /*
+ * On firmware >= 0x13 the EC_STATUS_WLAN has it's
+ * original meaning of Wifi status and no more the
+ * wifi button status so we have to ignore the event
+ * on theses versions
+ */
+ if (state && (gkeys[i].key_code == KEY_WLAN) && (data->version < 0x13)) {
+ mutex_lock(&data->mutex);
+ ec_wlan_en(client, !ec_wlan_status(client));
+ if (gpio16)
+ gpio_set_value(SM502_WLAN_ON, !ec_wlan_status(client));
+ mutex_unlock(&data->mutex);
+ }
+
+ input_event(input, gkeys[i].type, gkeys[i].key_code, !!state);
+ input_sync(input);
+ }
+ }
+}
+
+static int gdium_laptop_input_init(struct gdium_laptop_data *data)
+{
+ struct i2c_client *client = data->client;
+ struct input_dev *input;
+ int ret, i;
+
+ data->input_polldev = input_allocate_polled_device();
+ if (!data->input_polldev) {
+ ret = -ENOMEM;
+ goto err;
+ }
+
+ input = data->input_polldev->input;
+ input->evbit[0] = BIT(EV_KEY) | BIT_MASK(EV_PWR) | BIT_MASK(EV_SW);
+ data->input_polldev->poll = gdium_laptop_keys_poll;
+ data->input_polldev->poll_interval = SCAN_INTERVAL;
+ data->input_polldev->private = data;
+ input->name = "gdium-keys";
+ input->dev.parent = &client->dev;
+
+ input->id.bustype = BUS_HOST;
+ input->id.vendor = 0x0001;
+ input->id.product = 0x0001;
+ input->id.version = 0x0100;
+
+ for (i = 0; i < ARRAY_SIZE(gkeys); i++)
+ input_set_capability(input, gkeys[i].type, gkeys[i].key_code);
+
+ ret = input_register_polled_device(data->input_polldev);
+ if (ret) {
+ dev_err(&client->dev, "Unable to register button device\n");
+ goto err_poll_dev;
+ }
+
+ return 0;
+
+err_poll_dev:
+ input_free_polled_device(data->input_polldev);
+err:
+ return ret;
+}
+
+static void gdium_laptop_input_exit(struct gdium_laptop_data *data)
+{
+ input_unregister_polled_device(data->input_polldev);
+ input_free_polled_device(data->input_polldev);
+}
+
+/**********************************************************************/
+/* Battery management */
+/**********************************************************************/
+static int gdium_ac_get_props(struct power_supply *psy,
+ enum power_supply_property psp,
+ union power_supply_propval *val)
+{
+ char status;
+ struct gdium_laptop_data *data = container_of(psy, struct gdium_laptop_data, gdium_ac);
+ int ret = 0;
+
+ if (!data) {
+ pr_err("gdium-ac: gdium_laptop_data not found\n");
+ return -EINVAL;
+ }
+
+ status = data->status;
+ switch (psp) {
+ case POWER_SUPPLY_PROP_ONLINE:
+ val->intval = !!(status & EC_STATUS_ADAPT);
+ break;
+ default:
+ ret = -EINVAL;
+ break;
+ }
+
+ return ret;
+}
+
+#undef RET
+#define RET (val->intval)
+
+static int gdium_battery_get_props(struct power_supply *psy,
+ enum power_supply_property psp,
+ union power_supply_propval *val)
+{
+ char status, ctrl;
+ struct gdium_laptop_data *data = container_of(psy, struct gdium_laptop_data, gdium_battery);
+ int percentage_capacity = 0, charge_now = 0, time_to_empty = 0;
+ int ret = 0, tmp;
+
+ if (!data) {
+ pr_err("gdium-battery: gdium_laptop_data not found\n");
+ return -EINVAL;
+ }
+
+ status = data->status;
+ ctrl = data->ctrl;
+ switch (psp) {
+ case POWER_SUPPLY_PROP_CHARGE_FULL_DESIGN:
+ /* uAh */
+ RET = 5000000;
+ break;
+ case POWER_SUPPLY_PROP_CURRENT_NOW:
+ case POWER_SUPPLY_PROP_TIME_TO_EMPTY_NOW:
+ /* This formula is gotten by gnuplot with the statistic data */
+ time_to_empty = (data->battery_level - BAT_MIN_MV + BAT_READ_ERROR_MV) * 113 - 29870;
+ if (psp == POWER_SUPPLY_PROP_TIME_TO_EMPTY_NOW) {
+ /* seconds */
+ RET = time_to_empty / 10;
+ break;
+ }
+ /* fall through */
+ case POWER_SUPPLY_PROP_CHARGE_NOW:
+ case POWER_SUPPLY_PROP_CAPACITY: {
+ tmp = data->battery_level * 1000;
+ /* > BAT_MIN to avoid negative values */
+ percentage_capacity = 0;
+ if ((status & EC_STATUS_BATID) && (tmp > BAT_MIN))
+ percentage_capacity = (tmp-BAT_MIN)*100/(BAT_MAX-BAT_MIN);
+
+ if (percentage_capacity > 100)
+ percentage_capacity = 100;
+
+ if (psp == POWER_SUPPLY_PROP_CAPACITY) {
+ RET = percentage_capacity;
+ break;
+ }
+ charge_now = 50000 * percentage_capacity;
+ if (psp == POWER_SUPPLY_PROP_CHARGE_NOW) {
+ /* uAh */
+ RET = charge_now;
+ break;
+ }
+ } /* fall through */
+ case POWER_SUPPLY_PROP_STATUS: {
+ if (status & EC_STATUS_ADAPT)
+ if (ctrl & EC_CTRL_CHARGE_EN)
+ RET = POWER_SUPPLY_STATUS_CHARGING;
+ else
+ RET = POWER_SUPPLY_STATUS_NOT_CHARGING;
+ else
+ RET = POWER_SUPPLY_STATUS_DISCHARGING;
+
+ if (psp == POWER_SUPPLY_PROP_STATUS)
+ break;
+ /* mAh -> µA */
+ switch (RET) {
+ case POWER_SUPPLY_STATUS_CHARGING:
+ RET = -(data->charge_cmd == 2) ? 1400000 : 250000;
+ break;
+ case POWER_SUPPLY_STATUS_DISCHARGING:
+ RET = charge_now / time_to_empty * 36000;
+ break;
+ case POWER_SUPPLY_STATUS_NOT_CHARGING:
+ default:
+ RET = 0;
+ break;
+ }
+ } break;
+ case POWER_SUPPLY_PROP_VOLTAGE_MAX_DESIGN:
+ RET = BAT_MAX+BAT_READ_ERROR;
+ break;
+ case POWER_SUPPLY_PROP_VOLTAGE_MIN_DESIGN:
+ RET = BAT_MIN-BAT_READ_ERROR;
+ break;
+ case POWER_SUPPLY_PROP_VOLTAGE_NOW:
+ /* mV -> uV */
+ RET = data->battery_level * 1000;
+ break;
+ case POWER_SUPPLY_PROP_PRESENT:
+#if CONFIG_GDIUM_VERSION > 2
+ RET = !!(status & EC_STATUS_BATID);
+#else
+ RET = !!(data->battery_level > BAT_VOLT_PRESENT);
+#endif
+ break;
+ case POWER_SUPPLY_PROP_CAPACITY_LEVEL:
+ tmp = data->battery_level * 1000;
+ RET = POWER_SUPPLY_CAPACITY_LEVEL_UNKNOWN;
+ if (status & EC_STATUS_BATID) {
+ if (tmp >= BAT_MAX) {
+ RET = POWER_SUPPLY_CAPACITY_LEVEL_HIGH;
+ if (tmp >= BAT_MAX+BAT_READ_ERROR)
+ RET = POWER_SUPPLY_CAPACITY_LEVEL_FULL;
+ } else if (tmp <= BAT_MIN+BAT_READ_ERROR) {
+ RET = POWER_SUPPLY_CAPACITY_LEVEL_LOW;
+ if (tmp <= BAT_MIN)
+ RET = POWER_SUPPLY_CAPACITY_LEVEL_CRITICAL;
+ } else
+ RET = POWER_SUPPLY_CAPACITY_LEVEL_NORMAL;
+ }
+ break;
+ case POWER_SUPPLY_PROP_CHARGE_TYPE:
+ if (ctrl & EC_CTRL_TRICKLE)
+ RET = POWER_SUPPLY_CHARGE_TYPE_TRICKLE;
+ else if (ctrl & EC_CTRL_CHARGE_EN)
+ RET = POWER_SUPPLY_CHARGE_TYPE_FAST;
+ else
+ RET = POWER_SUPPLY_CHARGE_TYPE_NONE;
+ break;
+ case POWER_SUPPLY_PROP_CURRENT_MAX:
+ /* 1.4A ? */
+ RET = 1400000;
+ break;
+ default:
+ break;
+ }
+
+ return ret;
+}
+#undef RET
+
+static enum power_supply_property gdium_ac_props[] = {
+ POWER_SUPPLY_PROP_ONLINE,
+};
+
+static enum power_supply_property gdium_battery_props[] = {
+ POWER_SUPPLY_PROP_STATUS,
+ POWER_SUPPLY_PROP_PRESENT,
+ POWER_SUPPLY_PROP_CHARGE_FULL_DESIGN,
+ POWER_SUPPLY_PROP_CHARGE_NOW,
+ POWER_SUPPLY_PROP_TIME_TO_EMPTY_NOW,
+ POWER_SUPPLY_PROP_VOLTAGE_MIN_DESIGN,
+ POWER_SUPPLY_PROP_VOLTAGE_MAX_DESIGN,
+ POWER_SUPPLY_PROP_VOLTAGE_NOW,
+ POWER_SUPPLY_PROP_CURRENT_MAX,
+ POWER_SUPPLY_PROP_CURRENT_NOW,
+ POWER_SUPPLY_PROP_CAPACITY,
+ POWER_SUPPLY_PROP_CAPACITY_LEVEL,
+ POWER_SUPPLY_PROP_CHARGE_TYPE,
+};
+
+static void gdium_laptop_battery_work(struct work_struct *work)
+{
+ struct gdium_laptop_data *data = container_of(work, struct gdium_laptop_data, work.work);
+ struct i2c_client *client;
+ int ret;
+ char old_status, old_charge_cmd;
+ char present;
+ s32 status;
+
+ mutex_lock(&data->mutex);
+ client = data->client;
+ status = ec_read_status(client);
+ ret = ec_read_battery(client);
+
+ if ((status < 0) || (ret < 0))
+ goto i2c_read_error;
+
+ old_status = data->status;
+ old_charge_cmd = data->charge_cmd;
+ data->status = status;
+
+ /*
+ * Charge only if :
+ * - battery present
+ * - ac adapter plugged in
+ * - battery not fully charged
+ */
+#if CONFIG_GDIUM_VERSION > 2
+ present = !!(data->status & EC_STATUS_BATID);
+#else
+ present = !!(ret > BAT_VOLT_PRESENT);
+#endif
+ data->battery_level = 0;
+ if (present) {
+ data->battery_level = (unsigned int)ret;
+ if (data->status & EC_STATUS_ADAPT)
+ data->battery_level -= BAT_READ_ERROR_MV;
+ }
+
+ data->charge_cmd = 0;
+ if ((data->status & EC_STATUS_ADAPT) && present && (data->battery_level <= BAT_MAX_MV))
+ data->charge_cmd = (ret < BAT_TRICKLE_EN) ? 2 : 3;
+
+ ec_charge_en(client, (data->charge_cmd >> 1) & 1, data->charge_cmd & 1);
+
+ /*
+ * data->ctrl must be set _after_ calling ec_charge_en as this will change the
+ * control register content
+ */
+ data->ctrl = ec_read_ctrl(client);
+
+ if ((data->status & EC_STATUS_ADAPT) != (old_status & EC_STATUS_ADAPT)) {
+ power_supply_changed(&data->gdium_ac);
+ /* Send charging/discharging state change */
+ power_supply_changed(&data->gdium_battery);
+ } else if ((data->status & EC_STATUS_ADAPT) &&
+ ((old_charge_cmd&2) != (data->charge_cmd&2)))
+ power_supply_changed(&data->gdium_battery);
+
+i2c_read_error:
+ mutex_unlock(&data->mutex);
+ queue_delayed_work(data->workqueue, &data->work, msecs_to_jiffies(BAT_SCAN_INTERVAL));
+}
+
+static int gdium_laptop_battery_init(struct gdium_laptop_data *data)
+{
+ int ret;
+
+ data->bat_pdev = platform_device_register_simple("gdium-battery", 0, NULL, 0);
+ if (IS_ERR(data->bat_pdev))
+ return PTR_ERR(data->bat_pdev);
+
+ data->gdium_battery.name = data->bat_pdev->name;
+ data->gdium_battery.properties = gdium_battery_props;
+ data->gdium_battery.num_properties = ARRAY_SIZE(gdium_battery_props);
+ data->gdium_battery.get_property = gdium_battery_get_props;
+ data->gdium_battery.use_for_apm = 1;
+
+ ret = power_supply_register(&data->bat_pdev->dev, &data->gdium_battery);
+ if (ret)
+ goto err_platform;
+
+ data->gdium_ac.name = "gdium-ac";
+ data->gdium_ac.type = POWER_SUPPLY_TYPE_MAINS;
+ data->gdium_ac.properties = gdium_ac_props;
+ data->gdium_ac.num_properties = ARRAY_SIZE(gdium_ac_props);
+ data->gdium_ac.get_property = gdium_ac_get_props;
+/* data->gdium_ac.use_for_apm_ac = 1, */
+
+ ret = power_supply_register(&data->bat_pdev->dev, &data->gdium_ac);
+ if (ret)
+ goto err_battery;
+
+ if (!ec) {
+ INIT_DELAYED_WORK(&data->work, gdium_laptop_battery_work);
+ data->workqueue = create_singlethread_workqueue("gdium-battery-work");
+ if (!data->workqueue) {
+ ret = -ESRCH;
+ goto err_work;
+ }
+ queue_delayed_work(data->workqueue, &data->work, msecs_to_jiffies(BAT_SCAN_INTERVAL));
+ }
+
+ return 0;
+
+err_work:
+err_battery:
+ power_supply_unregister(&data->gdium_battery);
+err_platform:
+ platform_device_unregister(data->bat_pdev);
+
+ return ret;
+}
+static void gdium_laptop_battery_exit(struct gdium_laptop_data *data)
+{
+ if (!ec) {
+ cancel_rearming_delayed_workqueue(data->workqueue, &data->work);
+ destroy_workqueue(data->workqueue);
+ }
+ power_supply_unregister(&data->gdium_battery);
+ power_supply_unregister(&data->gdium_ac);
+ platform_device_unregister(data->bat_pdev);
+}
+
+/* Debug fs */
+static int gdium_laptop_regs_show(struct seq_file *s, void *p)
+{
+ struct gdium_laptop_data *data = s->private;
+ struct i2c_client *client = data->client;
+
+ mutex_lock(&data->mutex);
+ seq_printf(s, "Version : 0x%02x\n", (unsigned char)ec_read_version(client));
+ seq_printf(s, "Status : 0x%02x\n", (unsigned char)ec_read_status(client));
+ seq_printf(s, "Ctrl : 0x%02x\n", (unsigned char)ec_read_ctrl(client));
+ seq_printf(s, "Sign : 0x%02x\n", (unsigned char)ec_read_sign(client));
+ seq_printf(s, "Bat Lo : 0x%02x\n", (unsigned char)i2c_smbus_read_byte_data(client, EC_BAT_LOW));
+ seq_printf(s, "Bat Hi : 0x%02x\n", (unsigned char)i2c_smbus_read_byte_data(client, EC_BAT_HIGH));
+ seq_printf(s, "Battery : %d uV\n", (unsigned int)ec_read_battery(client) * 1000);
+ seq_printf(s, "Charge cmd : %s %s\n", data->charge_cmd & 2 ? "C" : " ", data->charge_cmd & 1 ? "T" : " ");
+
+ mutex_unlock(&data->mutex);
+ return 0;
+}
+
+static int gdium_laptop_regs_open(struct inode *inode,
+ struct file *file)
+{
+ return single_open(file, gdium_laptop_regs_show, inode->i_private);
+}
+
+static const struct file_operations gdium_laptop_regs_fops = {
+ .open = gdium_laptop_regs_open,
+ .read = seq_read,
+ .llseek = seq_lseek,
+ .release = single_release,
+ .owner = THIS_MODULE,
+};
+
+
+static int gdium_laptop_probe(struct i2c_client *client, const struct i2c_device_id *id)
+{
+ struct gdium_laptop_data *data;
+ int ret;
+
+ if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_BYTE_DATA)) {
+ dev_err(&client->dev,
+ "%s: no smbus_byte support !\n", __func__);
+ return -ENODEV;
+ }
+
+ data = kzalloc(sizeof(struct gdium_laptop_data), GFP_KERNEL);
+ if (!data)
+ return -ENOMEM;
+
+ i2c_set_clientdata(client, data);
+ data->client = client;
+ mutex_init(&data->mutex);
+
+ ret = ec_read_version(client);
+ if (ret < 0)
+ goto err_alloc;
+
+ data->version = (unsigned char)ret;
+
+ ret = gdium_laptop_input_init(data);
+ if (ret)
+ goto err_alloc;
+
+ ret = gdium_laptop_battery_init(data);
+ if (ret)
+ goto err_input;
+
+
+ if (!ec) {
+ ret = ec_write_sign(client, EC_SIGN_OS);
+ if (ret)
+ goto err_sign;
+ }
+
+ if (gpio16) {
+ ret = gpio_request(SM502_WLAN_ON, "wlan-on");
+ if (ret < 0)
+ goto err_sign;
+ gpio_set_value(SM502_WLAN_ON, ec_wlan_status(client));
+ gpio_direction_output(SM502_WLAN_ON, 1);
+ }
+
+ dev_info(&client->dev, "Found firmware 0x%02x\n", data->version);
+ data->debugfs = debugfs_create_file("gdium_laptop", S_IFREG | S_IRUGO,
+ NULL, data, &gdium_laptop_regs_fops);
+
+ return 0;
+
+err_sign:
+ gdium_laptop_battery_exit(data);
+err_input:
+ gdium_laptop_input_exit(data);
+err_alloc:
+ kfree(data);
+ return ret;
+}
+
+static int gdium_laptop_remove(struct i2c_client *client)
+{
+ struct gdium_laptop_data *data = i2c_get_clientdata(client);
+
+ if (gpio16)
+ gpio_free(SM502_WLAN_ON);
+ ec_write_sign(client, EC_SIGN_EC);
+ if (data->debugfs)
+ debugfs_remove(data->debugfs);
+
+ gdium_laptop_battery_exit(data);
+ gdium_laptop_input_exit(data);
+
+ kfree(data);
+ return 0;
+}
+
+#ifdef CONFIG_PM
+static int gdium_laptop_suspend(struct i2c_client *client, pm_message_t msg)
+{
+ struct gdium_laptop_data *data = i2c_get_clientdata(client);
+
+ if (!ec)
+ cancel_rearming_delayed_workqueue(data->workqueue, &data->work);
+ return 0;
+}
+
+static int gdium_laptop_resume(struct i2c_client *client)
+{
+ struct gdium_laptop_data *data = i2c_get_clientdata(client);
+
+ if (!ec)
+ queue_delayed_work(data->workqueue, &data->work, msecs_to_jiffies(BAT_SCAN_INTERVAL));
+ return 0;
+}
+#else
+#define gdium_laptop_suspend NULL
+#define gdium_laptop_resume NULL
+#endif
+static const struct i2c_device_id gdium_id[] = {
+ { "gdium-laptop" },
+ {},
+};
+MODULE_DEVICE_TABLE(i2c, gdium_id);
+
+static struct i2c_driver gdium_laptop_driver = {
+ .driver = {
+ .name = "gdium-laptop",
+ .owner = THIS_MODULE,
+ },
+ .probe = gdium_laptop_probe,
+ .remove = gdium_laptop_remove,
+ .shutdown = gdium_laptop_remove,
+ .suspend = gdium_laptop_suspend,
+ .resume = gdium_laptop_resume,
+ .id_table = gdium_id,
+};
+
+static int __init gdium_laptop_init(void)
+{
+ return i2c_add_driver(&gdium_laptop_driver);
+}
+
+static void __exit gdium_laptop_exit(void)
+{
+ i2c_del_driver(&gdium_laptop_driver);
+}
+
+module_init(gdium_laptop_init);
+module_exit(gdium_laptop_exit);
+
+MODULE_AUTHOR("Arnaud Patard <apatard@mandriva.com>");
+MODULE_DESCRIPTION("Gdium laptop extras");
+MODULE_LICENSE("GPL");
diff --git a/drivers/platform/mips/lynloong_pc.c b/drivers/platform/mips/lynloong_pc.c
new file mode 100644
index 0000000..e55fc63
--- /dev/null
+++ b/drivers/platform/mips/lynloong_pc.c
@@ -0,0 +1,514 @@
+/*
+ * 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;
+ struct backlight_properties props;
+
+ /* 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);
+
+ memset(&props, 0, sizeof(struct backlight_properties));
+ props.max_brightness = MAX_BRIGHTNESS;
+ props.type = BACKLIGHT_PLATFORM;
+ lynloong_backlight_dev = backlight_device_register("backlight0", NULL,
+ NULL, &backlight_ops, &props);
+
+ if (IS_ERR(lynloong_backlight_dev)) {
+ ret = PTR_ERR(lynloong_backlight_dev);
+ return ret;
+ }
+
+ 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 --git a/drivers/platform/mips/yeeloong_ecrom.c b/drivers/platform/mips/yeeloong_ecrom.c
new file mode 100644
index 0000000..2f4d8fe
--- /dev/null
+++ b/drivers/platform/mips/yeeloong_ecrom.c
@@ -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 --git a/drivers/platform/mips/yeeloong_laptop.c b/drivers/platform/mips/yeeloong_laptop.c
new file mode 100644
index 0000000..c0fd248
--- /dev/null
+++ b/drivers/platform/mips/yeeloong_laptop.c
@@ -0,0 +1,1349 @@
+/*
+ * 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/lcd.h> /* for lcd 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 <linux/reboot.h> /* for register_reboot_notifier */
+#include <linux/suspend.h> /* for register_pm_notifier */
+
+#include <cs5536/cs5536.h>
+
+#include <loongson.h> /* for loongson_cmdline */
+#include <ec_kb3310b.h>
+
+/* common function */
+#define EC_VER_LEN 64
+
+static int ec_version_before(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';
+ }
+
+ return (strncasecmp(ec_ver, version, 64) < 0);
+}
+
+/* backlight subdriver */
+#define MIN_BRIGHTNESS 1
+#define MAX_BRIGHTNESS 8
+
+static int yeeloong_set_brightness(struct backlight_device *bd)
+{
+ unsigned char level;
+ static unsigned char old_level;
+
+ level = (bd->props.fb_blank == FB_BLANK_UNBLANK &&
+ bd->props.power == FB_BLANK_UNBLANK) ?
+ bd->props.brightness : 0;
+
+ level = SENSORS_LIMIT(level, MIN_BRIGHTNESS, MAX_BRIGHTNESS);
+
+ /* Avoid to modify the brightness when EC is tuning it */
+ if (old_level != level) {
+ if (ec_read(REG_DISPLAY_BRIGHTNESS) == old_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;
+ struct backlight_properties props;
+
+ memset(&props, 0, sizeof(struct backlight_properties));
+ props.max_brightness = MAX_BRIGHTNESS;
+ props.type = BACKLIGHT_PLATFORM;
+ yeeloong_backlight_dev = backlight_device_register("backlight0", NULL,
+ NULL, &backlight_ops, &props);
+
+ if (IS_ERR(yeeloong_backlight_dev)) {
+ ret = PTR_ERR(yeeloong_backlight_dev);
+ yeeloong_backlight_dev = NULL;
+ return ret;
+ }
+
+ 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 RET (val->intval)
+
+#define BAT_CAP_CRITICAL 5
+#define BAT_CAP_HIGH 95
+
+#define get_bat(type) \
+ ec_read(REG_BAT_##type)
+
+#define get_bat_l(type) \
+ ((get_bat(type##_HIGH) << 8) | get_bat(type##_LOW))
+
+static int yeeloong_get_ac_props(struct power_supply *psy,
+ enum power_supply_property psp,
+ union power_supply_propval *val)
+{
+ if (psp == POWER_SUPPLY_PROP_ONLINE)
+ RET = !!(get_bat(POWER) & BIT_BAT_POWER_ACIN);
+
+ 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,
+};
+
+static inline bool is_bat_in(void)
+{
+ return !!(get_bat(STATUS) & BIT_BAT_STATUS_IN);
+}
+
+static int get_bat_temp(void)
+{
+ return get_bat_l(TEMPERATURE) * 1000;
+}
+
+static int get_bat_current(void)
+{
+ return -(s16)get_bat_l(CURRENT);
+}
+
+static int get_bat_voltage(void)
+{
+ return get_bat_l(VOLTAGE);
+}
+
+static char *get_manufacturer(void)
+{
+ return (get_bat(VENDOR) == FLAG_BAT_VENDOR_SANYO) ? "SANYO" : "SIMPLO";
+}
+
+static int get_relative_cap(void)
+{
+ /*
+ * When the relative capacity becomes 2, the hardware is observed to
+ * have been turned off forcely. so, we must tune it be suitable to
+ * make the software do related actions.
+ */
+ int tmp = get_bat_l(RELATIVE_CAP);
+
+ if (tmp <= (BAT_CAP_CRITICAL * 2))
+ tmp -= 3;
+
+ return tmp;
+}
+
+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:
+ /* mV -> µV */
+ RET = get_bat_l(DESIGN_VOL) * 1000;
+ break;
+ case POWER_SUPPLY_PROP_CHARGE_FULL_DESIGN:
+ /* mAh->µAh */
+ RET = get_bat_l(DESIGN_CAP) * 1000;
+ break;
+ case POWER_SUPPLY_PROP_CHARGE_FULL:
+ /* µAh */
+ RET = get_bat_l(FULLCHG_CAP) * 1000;
+ break;
+ case POWER_SUPPLY_PROP_MANUFACTURER:
+ val->strval = get_manufacturer();
+ break;
+ /* Dynamic information */
+ case POWER_SUPPLY_PROP_PRESENT:
+ RET = is_bat_in();
+ break;
+ case POWER_SUPPLY_PROP_CURRENT_NOW:
+ /* mA -> µA */
+ RET = is_bat_in() ? get_bat_current() * 1000 : 0;
+ break;
+ case POWER_SUPPLY_PROP_VOLTAGE_NOW:
+ /* mV -> µV */
+ RET = is_bat_in() ? get_bat_voltage() * 1000 : 0;
+ break;
+ case POWER_SUPPLY_PROP_TEMP:
+ /* Celcius */
+ RET = is_bat_in() ? get_bat_temp() : 0;
+ break;
+ case POWER_SUPPLY_PROP_CAPACITY:
+ RET = is_bat_in() ? get_relative_cap() : 0;
+ break;
+ case POWER_SUPPLY_PROP_CAPACITY_LEVEL: {
+ int status;
+
+ if (!is_bat_in()) {
+ RET = POWER_SUPPLY_CAPACITY_LEVEL_UNKNOWN;
+ break;
+ }
+
+ status = get_bat(STATUS);
+ RET = POWER_SUPPLY_CAPACITY_LEVEL_NORMAL;
+
+ if (unlikely(status & BIT_BAT_STATUS_DESTROY)) {
+ RET = POWER_SUPPLY_CAPACITY_LEVEL_UNKNOWN;
+ break;
+ }
+
+ if (status & BIT_BAT_STATUS_FULL)
+ RET = POWER_SUPPLY_CAPACITY_LEVEL_FULL;
+ else {
+ int curr_cap = get_relative_cap();
+
+ if (status & BIT_BAT_STATUS_LOW) {
+ RET = POWER_SUPPLY_CAPACITY_LEVEL_LOW;
+ if (curr_cap <= BAT_CAP_CRITICAL)
+ RET = POWER_SUPPLY_CAPACITY_LEVEL_CRITICAL;
+ } else if (curr_cap >= BAT_CAP_HIGH)
+ RET = POWER_SUPPLY_CAPACITY_LEVEL_HIGH;
+ }
+ } break;
+ case POWER_SUPPLY_PROP_TIME_TO_EMPTY_NOW:
+ /* seconds */
+ RET = is_bat_in() ? (get_relative_cap() - 3) * 54 + 142 : 0;
+ break;
+ case POWER_SUPPLY_PROP_STATUS: {
+ int charge = get_bat(CHARGE);
+
+ RET = POWER_SUPPLY_STATUS_UNKNOWN;
+ if (charge & FLAG_BAT_CHARGE_DISCHARGE)
+ RET = POWER_SUPPLY_STATUS_DISCHARGING;
+ else if (charge & FLAG_BAT_CHARGE_CHARGE)
+ RET = POWER_SUPPLY_STATUS_CHARGING;
+ } break;
+ case POWER_SUPPLY_PROP_HEALTH: {
+ int status;
+
+ if (!is_bat_in()) {
+ RET = POWER_SUPPLY_HEALTH_UNKNOWN;
+ break;
+ }
+
+ status = get_bat(STATUS);
+ RET = POWER_SUPPLY_HEALTH_GOOD;
+
+ if (status & (BIT_BAT_STATUS_DESTROY |
+ BIT_BAT_STATUS_LOW))
+ RET = POWER_SUPPLY_HEALTH_DEAD;
+ if (get_bat(CHARGE_STATUS) &
+ BIT_BAT_CHARGE_STATUS_OVERTEMP)
+ RET = POWER_SUPPLY_HEALTH_OVERHEAT;
+ } break;
+ case POWER_SUPPLY_PROP_CHARGE_NOW: /* 1/100(%)*1000 µAh */
+ RET = get_relative_cap() * get_bat_l(FULLCHG_CAP) * 10;
+ break;
+ default:
+ return -EINVAL;
+ }
+ return 0;
+}
+#undef RET
+
+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_CHARGE_FULL,
+ POWER_SUPPLY_PROP_CHARGE_NOW,
+ 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
+
+#define get_fan(type) \
+ ec_read(REG_FAN_##type)
+
+#define set_fan(type, val) \
+ ec_write(REG_FAN_##type, val)
+
+static inline int get_fan_speed_level(void)
+{
+ return get_fan(SPEED_LEVEL);
+}
+static inline void set_fan_speed_level(int speed)
+{
+ set_fan(SPEED_LEVEL, speed);
+}
+
+static inline int get_fan_mode(void)
+{
+ return get_fan(AUTO_MAN_SWITCH);
+}
+static inline void set_fan_mode(int mode)
+{
+ set_fan(AUTO_MAN_SWITCH, mode);
+}
+
+/*
+ * 3 different modes: Full speed(0); manual mode(1); auto mode(2)
+ */
+static int get_fan_pwm_enable(void)
+{
+ return (get_fan_mode() == BIT_FAN_AUTO) ? 2 :
+ (get_fan_speed_level() == MAX_FAN_SPEED) ? 0 : 1;
+}
+
+static void set_fan_pwm_enable(int mode)
+{
+ set_fan_mode((mode == 2) ? BIT_FAN_AUTO : BIT_FAN_MANUAL);
+ if (mode == 0)
+ set_fan_speed_level(MAX_FAN_SPEED);
+}
+
+static int get_fan_pwm(void)
+{
+ return get_fan_speed_level();
+}
+
+static void set_fan_pwm(int value)
+{
+ if (get_fan_mode() != BIT_FAN_MANUAL)
+ return;
+
+ value = SENSORS_LIMIT(value, MIN_FAN_SPEED, MAX_FAN_SPEED);
+
+ /* We must ensure the fan is on */
+ if (value > 0)
+ set_fan(CONTROL, ON);
+
+ set_fan_speed_level(value);
+}
+
+static inline int get_fan_speed(void)
+{
+ return ((get_fan(SPEED_HIGH) & 0x0f) << 8) | get_fan(SPEED_LOW);
+}
+
+static int get_fan_rpm(void)
+{
+ return FAN_SPEED_DIVIDER / get_fan_speed();
+}
+
+static int get_cpu_temp(void)
+{
+ return (s8)ec_read(REG_TEMPERATURE_VALUE) * 1000;
+}
+
+static int get_cpu_temp_max(void)
+{
+ return 60 * 1000;
+}
+
+static int get_bat_temp_alarm(void)
+{
+ return !!(get_bat(CHARGE_STATUS) & BIT_BAT_CHARGE_STATUS_OVERTEMP);
+}
+
+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_bat_temp, NULL);
+CREATE_SENSOR_ATTR(temp2_max_alarm, S_IRUGO, get_bat_temp_alarm, NULL);
+CREATE_SENSOR_ATTR(curr1_input, S_IRUGO, get_bat_current, NULL);
+CREATE_SENSOR_ATTR(in1_input, S_IRUGO, get_bat_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)) {
+ 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 */
+
+#define LCD 0
+#define CRT 1
+#define VOD_NUM 2 /* The total number of video output device*/
+
+static struct output_device *vod[VOD_NUM];
+
+static int vor[] = {REG_DISPLAY_LCD, REG_CRT_DETECT};
+
+static int get_vo_dev(struct output_device *od)
+{
+ int i, dev;
+
+ dev = -1;
+ for (i = 0; i < VOD_NUM; i++)
+ if (od == vod[i])
+ dev = i;
+
+ return dev;
+}
+
+static int vo_get_status(int dev)
+{
+ return ec_read(vor[dev]);
+}
+
+static int yeeloong_vo_get_status(struct output_device *od)
+{
+ int vd;
+
+ vd = get_vo_dev(od);
+ if (vd != -1)
+ return vo_get_status(vd);
+
+ return -ENODEV;
+}
+
+static void vo_set_state(int dev, int state)
+{
+ int addr;
+ unsigned long value;
+
+ switch (dev) {
+ case LCD:
+ addr = 0x31;
+ break;
+ case CRT:
+ addr = 0x21;
+ break;
+ default:
+ /* return directly if the wrong video output device */
+ return;
+ }
+
+ outb(addr, 0x3c4);
+ value = inb(0x3c5);
+
+ switch (dev) {
+ case LCD:
+ value |= (state ? 0x03 : 0x02);
+ break;
+ case CRT:
+ if (state)
+ clear_bit(7, &value);
+ else
+ set_bit(7, &value);
+ break;
+ default:
+ break;
+ }
+
+ outb(addr, 0x3c4);
+ outb(value, 0x3c5);
+
+ if (dev == LCD)
+ ec_write(REG_BACKLIGHT_CTRL, state);
+}
+
+static int yeeloong_vo_set_state(struct output_device *od)
+{
+ int vd;
+
+ vd = get_vo_dev(od);
+ if (vd == -1)
+ return -ENODEV;
+
+ if (vd == CRT && !vo_get_status(vd))
+ return 0;
+
+ vo_set_state(vd, !!od->request_state);
+
+ return 0;
+}
+
+static struct output_properties vop = {
+ .set_state = yeeloong_vo_set_state,
+ .get_status = yeeloong_vo_get_status,
+};
+
+static int yeeloong_vo_init(void)
+{
+ int ret, i;
+ char dev_name[VOD_NUM][4] = {"LCD", "CRT"};
+
+ /* Register video output device: lcd, crt */
+ for (i = 0; i < VOD_NUM; i++) {
+ vod[i] = video_output_register(dev_name[i], NULL, NULL, &vop);
+ if (IS_ERR(vod[i])) {
+ if (i != 0)
+ video_output_unregister(vod[i-1]);
+ ret = PTR_ERR(vod[i]);
+ vod[i] = NULL;
+ return ret;
+ }
+ }
+ /* Ensure LCD is on by default */
+ vo_set_state(LCD, ON);
+
+ /*
+ * Turn off CRT by default, and will be enabled when the CRT
+ * connectting event reported by SCI
+ */
+ vo_set_state(CRT, OFF);
+
+ return 0;
+}
+
+static void yeeloong_vo_exit(void)
+{
+ int i;
+
+ for (i = 0; i < VOD_NUM; i++) {
+ if (vod[i]) {
+ video_output_unregister(vod[i]);
+ vod[i] = NULL;
+ }
+ }
+}
+
+/* lcd subdriver */
+
+struct lcd_device *lcd[VOD_NUM];
+
+static int get_lcd_dev(struct lcd_device *ld)
+{
+ int i, dev;
+
+ dev = -1;
+ for (i = 0; i < VOD_NUM; i++)
+ if (ld == lcd[i])
+ dev = i;
+
+ return dev;
+}
+
+static int yeeloong_lcd_set_power(struct lcd_device *ld, int power)
+{
+ int dev = get_lcd_dev(ld);
+
+ if (power == FB_BLANK_UNBLANK)
+ vo_set_state(dev, ON);
+ if (power == FB_BLANK_POWERDOWN)
+ vo_set_state(dev, OFF);
+
+ return 0;
+}
+
+static int yeeloong_lcd_get_power(struct lcd_device *ld)
+{
+ return vo_get_status(get_lcd_dev(ld));
+}
+
+static struct lcd_ops lcd_ops = {
+ .set_power = yeeloong_lcd_set_power,
+ .get_power = yeeloong_lcd_get_power,
+};
+
+static int yeeloong_lcd_init(void)
+{
+ int ret, i;
+ char dev_name[VOD_NUM][4] = {"LCD", "CRT"};
+
+ /* Register video output device: lcd, crt */
+ for (i = 0; i < VOD_NUM; i++) {
+ lcd[i] = lcd_device_register(dev_name[i], NULL, NULL, &lcd_ops);
+ if (IS_ERR(lcd[i])) {
+ if (i != 0)
+ lcd_device_unregister(lcd[i-1]);
+ ret = PTR_ERR(lcd[i]);
+ lcd[i] = NULL;
+ return ret;
+ }
+ }
+#if 0
+ /* This has been done by the vide output driver */
+
+ /* Ensure LCD is on by default */
+ vo_set_state(LCD, ON);
+
+ /*
+ * Turn off CRT by default, and will be enabled when the CRT
+ * connectting event reported by SCI
+ */
+ vo_set_state(CRT, OFF);
+#endif
+ return 0;
+}
+
+static void yeeloong_lcd_exit(void)
+{
+ int i;
+
+ for (i = 0; i < VOD_NUM; i++) {
+ if (lcd[i]) {
+ lcd_device_unregister(lcd[i]);
+ lcd[i] = NULL;
+ }
+ }
+}
+
+/* hotkey subdriver */
+
+static struct input_dev *yeeloong_hotkey_dev;
+
+static atomic_t reboot_flag, sleep_flag;
+#define in_sleep() (&sleep_flag)
+#define in_reboot() (&reboot_flag)
+
+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_DISPLAYTOGGLE, { KEY_DISPLAYTOGGLE } }, /* Fn + F2 */
+ {KE_KEY, EVENT_SWITCHVIDEOMODE, { 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 int is_fake_event(u16 keycode)
+{
+ switch (keycode) {
+ case KEY_SLEEP:
+ case SW_LID:
+ return atomic_read(in_sleep()) | atomic_read(in_reboot());
+ break;
+ default:
+ break;
+ }
+ return 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)
+{
+ static int old_status;
+
+ /*
+ * LID is a switch button, so, two continuous same status should be
+ * ignored
+ */
+ if (old_status != status) {
+ input_report_switch(yeeloong_hotkey_dev, SW_LID, !status);
+ input_sync(yeeloong_hotkey_dev);
+ }
+ old_status = status;
+
+ return status;
+}
+
+static int crt_detect_handler(int status)
+{
+ /*
+ * When CRT is inserted, enable its output and disable the LCD output,
+ * otherwise, do reversely.
+ */
+ vo_set_state(CRT, status);
+ vo_set_state(LCD, !status);
+
+ return status;
+}
+
+static int displaytoggle_handler(int status)
+{
+ /* EC(>=PQ1D26) does this job for us, we can not do it again,
+ * otherwise, the brightness will not resume to the normal level! */
+ if (ec_version_before("EC_VER=PQ1D26"))
+ vo_set_state(LCD, status);
+
+ return status;
+}
+
+static int mypow(int x, int y)
+{
+ int i, j = x;
+
+ for (i = 1; i < y; i++)
+ j *= j;
+
+ return j;
+}
+
+static int switchvideomode_handler(int status)
+{
+ /* Default status: CRT|LCD = 0|1 = 1 */
+ static int bin_state = 1;
+ int i;
+
+ /*
+ * Only enable switch video output button
+ * when CRT is connected
+ */
+ if (!vo_get_status(CRT))
+ return 0;
+ /*
+ * 2. no CRT connected: LCD on, CRT off
+ * 3. BOTH on
+ * 0. BOTH off
+ * 1. LCD off, CRT on
+ */
+
+ bin_state++;
+ if (bin_state > mypow(2, VOD_NUM) - 1)
+ bin_state = 0;
+
+ for (i = 0; i < VOD_NUM; i++)
+ vo_set_state(i, bin_state & (1 << i));
+
+ return bin_state;
+}
+
+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;
+}
+
+struct sci_event {
+ int reg;
+ sci_handler handler;
+};
+
+static const struct sci_event se[] = {
+ [EVENT_AC_BAT] = {0, ac_bat_handler},
+ [EVENT_AUDIO_MUTE] = {REG_AUDIO_MUTE, NULL},
+ [EVENT_AUDIO_VOLUME] = {REG_AUDIO_VOLUME, NULL},
+ [EVENT_CRT_DETECT] = {REG_CRT_DETECT, crt_detect_handler},
+ [EVENT_CAMERA] = {REG_CAMERA_STATUS, camera_handler},
+ [EVENT_DISPLAYTOGGLE] = {REG_DISPLAY_LCD, displaytoggle_handler},
+ [EVENT_DISPLAY_BRIGHTNESS] = {REG_DISPLAY_BRIGHTNESS, NULL},
+ [EVENT_LID] = {REG_LID_DETECT, NULL},
+ [EVENT_SWITCHVIDEOMODE] = {0, switchvideomode_handler},
+ [EVENT_USB_OC0] = {REG_USB2_FLAG, usb0_handler},
+ [EVENT_USB_OC2] = {REG_USB2_FLAG, usb2_handler},
+};
+
+static void do_event_action(int event)
+{
+ int status;
+ struct key_entry *ke;
+ struct sci_event *sep;
+
+ sep = (struct sci_event *)&se[event];
+
+ if (sep->reg != 0)
+ status = ec_read(sep->reg);
+
+ if (sep->handler != NULL)
+ status = sep->handler(status);
+
+ pr_debug("%s: event: %d status: %d\n", __func__, event, status);
+
+ /* Report current key to user-space */
+ ke = get_event_key_entry(event, status);
+
+ /*
+ * Ignore the LID and SLEEP event when we are already in sleep or
+ * reboot state, this will avoid the recursive pm operations. but note:
+ * the report_lid_switch() called in arch/mips/loongson/lemote-2f/pm.c
+ * is necessary, because it is used to wake the system from sleep
+ * state. In the future, perhaps SW_LID should works like SLEEP, no
+ * need to function as a SWITCH, just report the state when the LID is
+ * closed is enough, this event can tell the software to "SLEEP", no
+ * need to tell the softwares when we are resuming from "SLEEP".
+ */
+ if (ke && !is_fake_event(ke->keycode)) {
+ 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 int notify_reboot(struct notifier_block *nb, unsigned long event, void *buf)
+{
+ switch (event) {
+ case SYS_RESTART:
+ case SYS_HALT:
+ case SYS_POWER_OFF:
+ atomic_set(in_reboot(), 1);
+ break;
+ default:
+ return NOTIFY_DONE;
+ }
+
+ return NOTIFY_OK;
+}
+
+static int notify_pm(struct notifier_block *nb, unsigned long event, void *buf)
+{
+ switch (event) {
+ case PM_HIBERNATION_PREPARE:
+ case PM_SUSPEND_PREPARE:
+ atomic_inc(in_sleep());
+ break;
+ case PM_POST_HIBERNATION:
+ case PM_POST_SUSPEND:
+ case PM_RESTORE_PREPARE: /* do we need this ?? */
+ atomic_dec(in_sleep());
+ break;
+ default:
+ return NOTIFY_DONE;
+ }
+
+ pr_debug("%s: event = %lu, in_sleep() = %d\n", __func__, event,
+ atomic_read(in_sleep()));
+
+ return NOTIFY_OK;
+}
+
+static struct notifier_block reboot_notifier = {
+ .notifier_call = notify_reboot,
+};
+
+static struct notifier_block pm_notifier = {
+ .notifier_call = notify_pm,
+};
+
+static int yeeloong_hotkey_init(void)
+{
+ int ret = 0;
+
+ ret = register_reboot_notifier(&reboot_notifier);
+ if (ret) {
+ pr_err("can't register reboot notifier\n");
+ goto end;
+ }
+
+ ret = register_pm_notifier(&pm_notifier);
+ if (ret) {
+ pr_err("can't register pm notifier\n");
+ goto free_reboot_notifier;
+ }
+
+ ret = sci_irq_init();
+ if (ret) {
+ pr_err("can't init SCI interrupt\n");
+ goto free_pm_notifier;
+ }
+
+ ret = request_threaded_irq(SCI_IRQ_NUM, NULL, &sci_irq_handler,
+ IRQF_ONESHOT, "sci", NULL);
+ if (ret) {
+ pr_err("can't thread SCI interrupt handler\n");
+ goto free_pm_notifier;
+ }
+
+ yeeloong_hotkey_dev = input_allocate_device();
+
+ if (!yeeloong_hotkey_dev) {
+ ret = -ENOMEM;
+ goto free_irq;
+ }
+
+ 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");
+ goto free_dev;
+ }
+
+ ret = input_register_device(yeeloong_hotkey_dev);
+ if (ret)
+ goto free_keymap;
+
+ /* Update the current status of LID */
+ report_lid_switch(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;
+
+free_keymap:
+ sparse_keymap_free(yeeloong_hotkey_dev);
+free_dev:
+ input_free_device(yeeloong_hotkey_dev);
+free_irq:
+ free_irq(SCI_IRQ_NUM, NULL);
+free_pm_notifier:
+ unregister_pm_notifier(&pm_notifier);
+free_reboot_notifier:
+ unregister_reboot_notifier(&reboot_notifier);
+end:
+ return ret;
+}
+
+static void yeeloong_hotkey_exit(void)
+{
+ /* Free irq */
+ free_irq(SCI_IRQ_NUM, NULL);
+
+#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)
+
+{
+ if (ec_version_before("EC_VER=PQ1D27"))
+ vo_set_state(LCD, OFF);
+ vo_set_state(CRT, OFF);
+ usb_ports_set(OFF);
+
+ return 0;
+}
+
+static int yeeloong_resume(struct device *dev)
+{
+ int ret;
+
+ if (ec_version_before("EC_VER=PQ1D27"))
+ vo_set_state(LCD, ON);
+ vo_set_state(CRT, ON);
+ usb_ports_set(ON);
+
+ ret = sci_irq_init();
+ if (ret)
+ return -EFAULT;
+
+ 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;
+ }
+
+#define yeeloong_init_drv(drv, alias) do { \
+ pr_info("Register yeeloong " alias " driver.\n"); \
+ ret = yeeloong_ ## drv ## _init(); \
+ if (ret) { \
+ pr_err("Fail to register yeeloong " alias " driver.\n"); \
+ yeeloong_ ## drv ## _exit(); \
+ return ret; \
+ } \
+} while (0)
+
+ yeeloong_init_drv(backlight, "backlight");
+ yeeloong_init_drv(bat, "battery and AC");
+ yeeloong_init_drv(hwmon, "hardware monitor");
+ yeeloong_init_drv(vo, "video output");
+ yeeloong_init_drv(lcd, "lcd output");
+ yeeloong_init_drv(hotkey, "hotkey input");
+
+ return 0;
+}
+
+static void __exit yeeloong_exit(void)
+{
+ yeeloong_hotkey_exit();
+ yeeloong_lcd_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 --git a/drivers/rtc/Kconfig b/drivers/rtc/Kconfig
index 5a538fc..1b45006 100644
--- a/drivers/rtc/Kconfig
+++ b/drivers/rtc/Kconfig
@@ -481,6 +481,7 @@
config RTC_DRV_CMOS
tristate "PC-style 'CMOS'"
depends on X86 || ALPHA || ARM || M32R || ATARI || PPC || MIPS || SPARC64
+ depends on !DEXXON_GDIUM
default y if X86
help
Say "yes" here to get direct support for the real time clock
diff --git a/drivers/rtc/rtc-cmos.c b/drivers/rtc/rtc-cmos.c
index 05beb6c..3bf1f21 100644
--- a/drivers/rtc/rtc-cmos.c
+++ b/drivers/rtc/rtc-cmos.c
@@ -691,8 +691,8 @@
/* FIXME:
* <asm-generic/rtc.h> doesn't know 12-hour mode either.
*/
- if (is_valid_irq(rtc_irq) && !(rtc_control & RTC_24H)) {
- dev_warn(dev, "only 24-hr 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 --git a/drivers/staging/sm7xx/smtcfb.c b/drivers/staging/sm7xx/smtcfb.c
index a164fc4..f3043cc 100644
--- a/drivers/staging/sm7xx/smtcfb.c
+++ b/drivers/staging/sm7xx/smtcfb.c
@@ -15,6 +15,8 @@
* 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
* - Verified on 2.6.19.2
@@ -106,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},
diff --git a/drivers/usb/host/ohci-hcd.c b/drivers/usb/host/ohci-hcd.c
index f9cf3f0..5fc952d 100644
--- a/drivers/usb/host/ohci-hcd.c
+++ b/drivers/usb/host/ohci-hcd.c
@@ -833,9 +833,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/drivers/usb/host/pci-quirks.c b/drivers/usb/host/pci-quirks.c
index a495d48..33d3f2fe 100644
--- a/drivers/usb/host/pci-quirks.c
+++ b/drivers/usb/host/pci-quirks.c
@@ -55,6 +55,16 @@
#define EHCI_USBLEGCTLSTS 4 /* legacy control/status */
#define EHCI_USBLEGCTLSTS_SOOE (1 << 13) /* SMI on ownership change */
+
+static inline int io_type_enabled(struct pci_dev *pdev, unsigned int mask)
+{
+ u16 cmd;
+ return !pci_read_config_word(pdev, PCI_COMMAND, &cmd) && (cmd & mask);
+}
+
+#define pio_enabled(dev) io_type_enabled(dev, PCI_COMMAND_IO)
+#define mmio_enabled(dev) io_type_enabled(dev, PCI_COMMAND_MEMORY)
+
/* AMD quirk use */
#define AB_REG_BAR_LOW 0xe0
#define AB_REG_BAR_HIGH 0xe1
@@ -348,6 +358,12 @@
}
EXPORT_SYMBOL_GPL(usb_amd_dev_put);
+static int __devinit mmio_resource_enabled(struct pci_dev *pdev, int idx)
+{
+ return pci_resource_start(pdev, idx) && mmio_enabled(pdev);
+}
+
+#if defined(CONFIG_USB_UHCI_HCD) || defined(CONFIG_USB_UHCI_HCD_MODULE)
/*
* Make sure the controller is completely inactive, unable to
* generate interrupts or do DMA.
@@ -429,15 +445,6 @@
}
EXPORT_SYMBOL_GPL(uhci_check_and_reset_hc);
-static inline int io_type_enabled(struct pci_dev *pdev, unsigned int mask)
-{
- u16 cmd;
- return !pci_read_config_word(pdev, PCI_COMMAND, &cmd) && (cmd & mask);
-}
-
-#define pio_enabled(dev) io_type_enabled(dev, PCI_COMMAND_IO)
-#define mmio_enabled(dev) io_type_enabled(dev, PCI_COMMAND_MEMORY)
-
static void __devinit quirk_usb_handoff_uhci(struct pci_dev *pdev)
{
unsigned long base = 0;
@@ -455,12 +462,11 @@
if (base)
uhci_check_and_reset_hc(pdev, base);
}
+#else
+#define quirk_usb_handoff_uhci(x) do { } while (0)
+#endif /* CONFIG_USB_UHCI_HCD* */
-static int __devinit mmio_resource_enabled(struct pci_dev *pdev, int idx)
-{
- return pci_resource_start(pdev, idx) && mmio_enabled(pdev);
-}
-
+#if defined(CONFIG_USB_OHCI_HCD) || defined(CONFIG_USB_OHCI_HCD_MODULE)
static void __devinit quirk_usb_handoff_ohci(struct pci_dev *pdev)
{
void __iomem *base;
@@ -534,7 +540,11 @@
iounmap(base);
}
+#else
+#define quirk_usb_handoff_ohci(x) do { } while(0)
+#endif /* CONFIG_USB_OHCI_HCD* */
+#if defined(CONFIG_USB_EHCI_HCD) || defined(CONFIG_USB_EHCI_HCD_MODULE)
static const struct dmi_system_id __devinitconst ehci_dmi_nohandoff_table[] = {
{
/* Pegatron Lucid (ExoPC) */
@@ -687,6 +697,9 @@
iounmap(base);
}
+#else
+#define quirk_usb_disable_ehci(x) do { } while (0)
+#endif /* CONFIG_USB_EHCI_HCD* */
/*
* handshake - spin reading a register until handshake completes
@@ -775,6 +788,7 @@
}
EXPORT_SYMBOL_GPL(usb_enable_xhci_ports);
+#if defined(CONFIG_USB_XHCI_HCD) || defined(CONFIG_USB_XHCI_HCD_MODULE)
/**
* PCI Quirks for xHCI.
*
@@ -869,6 +883,9 @@
iounmap(base);
}
+#else
+#define quirk_usb_handoff_xhci(x) do { } while (0)
+#endif /* CONFIG_USB_UHCI_HCD* */
static void __devinit quirk_usb_early_handoff(struct pci_dev *pdev)
{
diff --git a/drivers/usb/serial/option.c b/drivers/usb/serial/option.c
index d2becb9..abcf8d7 100644
--- a/drivers/usb/serial/option.c
+++ b/drivers/usb/serial/option.c
@@ -78,6 +78,9 @@
#define OPTION_PRODUCT_ETNA_KOI_MODEM 0x7100
#define OPTION_PRODUCT_GTM380_MODEM 0x7201
+#define HUAWO_VENDOR_ID 0x21F5
+#define HUAWO_PRODUCT_E1621 0x2008
+
#define HUAWEI_VENDOR_ID 0x12D1
#define HUAWEI_PRODUCT_E600 0x1001
#define HUAWEI_PRODUCT_E220 0x1003
@@ -572,6 +575,7 @@
{ USB_DEVICE(QUANTA_VENDOR_ID, QUANTA_PRODUCT_GLX) },
{ USB_DEVICE(QUANTA_VENDOR_ID, QUANTA_PRODUCT_GKE) },
{ USB_DEVICE(QUANTA_VENDOR_ID, QUANTA_PRODUCT_GLE) },
+ { USB_DEVICE(HUAWO_VENDOR_ID, HUAWO_PRODUCT_E1621) }, /* QUANTA 6500 chips, Unicom extensive use of this card */
{ USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E600, 0xff, 0xff, 0xff) },
{ USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E220, 0xff, 0xff, 0xff) },
{ USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E220BIS, 0xff, 0xff, 0xff) },
diff --git a/drivers/video/Makefile b/drivers/video/Makefile
index 8b83129..a19e44e 100644
--- a/drivers/video/Makefile
+++ b/drivers/video/Makefile
@@ -133,7 +133,7 @@
obj-$(CONFIG_FB_SH_MOBILE_MERAM) += sh_mobile_meram.o
obj-$(CONFIG_FB_SH_MOBILE_LCDC) += sh_mobile_lcdcfb.o
obj-$(CONFIG_FB_OMAP) += omap/
-obj-y += omap2/
+obj-$(CONFIG_FB_OMAP2) += omap2/
obj-$(CONFIG_XEN_FBDEV_FRONTEND) += xen-fbfront.o
obj-$(CONFIG_FB_CARMINE) += carminefb.o
obj-$(CONFIG_FB_MB862XX) += mb862xx/
diff --git a/include/linux/sm501.h b/include/linux/sm501.h
index 02fde50..a8677f0 100644
--- a/include/linux/sm501.h
+++ b/include/linux/sm501.h
@@ -27,6 +27,9 @@
extern unsigned long sm501_find_clock(struct device *dev,
int clksrc, unsigned long req_freq);
+extern void sm501_configure_gpio(struct device *dev,
+ unsigned int gpio, unsigned char mode);
+
/* sm501_misc_control
*
* Modify the SM501's MISC_CONTROL register
@@ -122,6 +125,7 @@
#define SM501_USE_AC97 (1<<7)
#define SM501_USE_I2S (1<<8)
#define SM501_USE_GPIO (1<<9)
+#define SM501_USE_PWM (1<<10)
#define SM501_USE_ALL (0xffffffff)
diff --git a/init/calibrate.c b/init/calibrate.c
index 24df797..fb1d404 100644
--- a/init/calibrate.c
+++ b/init/calibrate.c
@@ -21,6 +21,7 @@
__setup("lpj=", lpj_setup);
+#ifndef ARCH_HAS_PREPARED_LPJ
#ifdef ARCH_HAS_READ_CURRENT_TIMER
/* This routine uses the read_current_timer() routine and gets the
@@ -168,6 +169,7 @@
#else
static unsigned long __cpuinit calibrate_delay_direct(void) {return 0;}
#endif
+#endif /* ARCH_HAS_PREPARED_LPJ */
/*
* This is the number of bits of precision for the loops_per_jiffy. Each
@@ -265,6 +267,7 @@
lpj = lpj_fine;
pr_info("Calibrating delay loop (skipped), "
"value calculated using timer frequency.. ");
+#ifndef ARCH_HAS_PREPARED_LPJ
} else if ((lpj = calibrate_delay_direct()) != 0) {
if (!printed)
pr_info("Calibrating delay using timer "
@@ -273,7 +276,9 @@
if (!printed)
pr_info("Calibrating delay loop... ");
lpj = calibrate_delay_converge();
+#endif /* ARCH_HAS_PREPARED_LPJ */
}
+
per_cpu(cpu_loops_per_jiffy, this_cpu) = lpj;
if (!printed)
pr_cont("%lu.%02lu BogoMIPS (lpj=%lu)\n",
diff --git a/net/rfkill/core.c b/net/rfkill/core.c
index be90640..6157b67 100644
--- a/net/rfkill/core.c
+++ b/net/rfkill/core.c
@@ -112,7 +112,7 @@
static DEFINE_MUTEX(rfkill_global_mutex);
static LIST_HEAD(rfkill_fds); /* list of open fds of /dev/rfkill */
-static unsigned int rfkill_default_state = 1;
+static unsigned int rfkill_default_state; /* default: 0 = radio off */
module_param_named(default_state, rfkill_default_state, uint, 0444);
MODULE_PARM_DESC(default_state,
"Default initial state for all radio types, 0 = radio off");
diff --git a/scripts/recordmcount.pl b/scripts/recordmcount.pl
index 858966a..537470e 100755
--- a/scripts/recordmcount.pl
+++ b/scripts/recordmcount.pl
@@ -307,14 +307,33 @@
$cc .= " -m64";
$objcopy .= " -O elf64-sparc";
} elsif ($arch eq "mips") {
- # To enable module support, we need to enable the -mlong-calls option
- # of gcc for module, after using this option, we can not get the real
- # offset of the calling to _mcount, but the offset of the lui
- # instruction or the addiu one. herein, we record the address of the
- # first one, and then we can replace this instruction by a branch
- # instruction to jump over the profiling function to filter the
- # indicated functions, or swith back to the lui instruction to trace
- # them, which means dynamic tracing.
+ # <For kernel>
+ # To disable tracing, just replace "jal _mcount" with nop;
+ # to enable tracing, replace back. so, the offset 14 is
+ # needed to be recorded.
+ #
+ # 10: 03e0082d move at,ra
+ # 14: 0c000000 jal 0
+ # 14: R_MIPS_26 _mcount
+ # 14: R_MIPS_NONE *ABS*
+ # 14: R_MIPS_NONE *ABS*
+ # 18: 00020021 nop
+ #
+ # <For module>
+ #
+ # If no long call(-mlong-calls), the same to kernel.
+ #
+ # If the module space differs from the kernel space, long
+ # call is needed, as a result, the address of _mcount is
+ # needed to be recorded in a register and then jump from
+ # module space to kernel space via "jalr <register>". To
+ # disable tracing, "jalr <register>" can be replaced by
+ # nop; to enable tracing, replace it back. Since the
+ # offset of "jalr <register>" is not easy to be matched,
+ # the offset of the 1st _mcount below is recorded and to
+ # disable tracing, "lui v1, 0x0" is substituted with "b
+ # label", which jumps over "jalr <register>"; to enable
+ # tracing, replace it back.
#
# c: 3c030000 lui v1,0x0
# c: R_MIPS_HI16 _mcount
@@ -326,19 +345,12 @@
# 10: R_MIPS_NONE *ABS*
# 14: 03e0082d move at,ra
# 18: 0060f809 jalr v1
+ # label:
#
- # for the kernel:
- #
- # 10: 03e0082d move at,ra
- # 14: 0c000000 jal 0 <loongson_halt>
- # 14: R_MIPS_26 _mcount
- # 14: R_MIPS_NONE *ABS*
- # 14: R_MIPS_NONE *ABS*
- # 18: 00020021 nop
if ($is_module eq "0") {
$mcount_regex = "^\\s*([0-9a-fA-F]+): R_MIPS_26\\s+_mcount\$";
} else {
- $mcount_regex = "^\\s*([0-9a-fA-F]+): R_MIPS_HI16\\s+_mcount\$";
+ $mcount_regex = "^\\s*([0-9a-fA-F]+): R_MIPS_(HI16|26)\\s+_mcount\$";
}
$objdump .= " -Melf-trad".$endian."mips ";
diff --git a/scripts/sstrip.sh b/scripts/sstrip.sh
new file mode 100755
index 0000000..49b973a
--- /dev/null
+++ b/scripts/sstrip.sh
@@ -0,0 +1,59 @@
+#!/bin/bash
+# sstrip.sh -- strip the section table of an elf file
+#
+# Copyright (C) 2010 Wu Zhangjin, wuzhangjin@gmail.com
+# Licensed under the GPLv2
+#
+# Since the section table is useless for the embedded device, it can be
+# stripped out.
+#
+# Note: Some bootloader may check the section table but most of the time, it
+# may be not really used, If it really need the section table, it may need the
+# decompressed kernel image.
+
+# Usage
+
+function usage
+{
+cat <<EOF
+
+ # sstrip.sh -- strip the section table of an elf file
+
+ # Input: elf file
+ # Output: truncated elf file without the section table
+ # Usage: sstrip.sh /path/to/image
+
+EOF
+}
+
+# Do some necessary check
+IMAGE=$1
+
+[ -z "${IMAGE}" ] && echo "$0 : No indicated file to be stripped" && usage && exit -1
+[ ! -f "${IMAGE}" ] && echo "$0 : ${IMAGE} : No such file" && exit -1
+FILE_TYPE=`dd if=${IMAGE} bs=1 skip=1 count=3 2>/dev/null`
+[ "xELF" != "x${FILE_TYPE}" ] && echo "$0: ${IMAGE} is not an ELF file" && exit -1
+
+[ "x${V}" == "x1" ] && orig_filesz=`wc -c ${IMAGE} | cut -d' ' -f1`
+
+# Get the offset of the section table, here get the end of the program section
+filesz=$((`${OBJDUMP} -p ${IMAGE} | grep -m1 filesz | tr -s ' ' | cut -d' ' -f3`))
+
+# Truncate it via the dd tool
+dd if=/dev/null bs=1 of=${IMAGE} seek=${filesz} 2>/dev/null
+
+# Clear the section table information in the ELF header
+# The last 6 bytes of the ELF header are the section table information
+echo -ne "\x00\x00\x00\x00\x00\x00" | dd of=${IMAGE} bs=1 seek=46 count=6 conv=notrunc 2>/dev/null
+
+# Debug
+if [ "x${V}" == "x1" ]; then
+ echo "----------------------------------------------------------------"
+ echo "Strip the section table at ${filesz} of ${IMAGE}"
+ echo "----------------------------------------------------------------"
+ echo " sstrip: $0"
+ echo " objdump: ${OBJDUMP}"
+ echo "original size: ${orig_filesz}"
+ echo "current size: ${filesz}"
+ echo "reduced size: $((${orig_filesz} - ${filesz}))"
+fi